pythondjangodjango-querysetfieldmatching

How to check if a django queryset has a matching manytomany + foreignkey?


I try to check - in Django - if a user-made queryset has two fields which match 100%.

class Foo(models.Model):
    # ...
    free_field = models.ForeignKey(FreeModel, ...)
    must_match_m2m_field = models.ManyToManyField(ManyModel, ...)
    must_match_fk_field = models.ForeignKey(BarModel, ...)
    # ...

# user generates a queryset of Foo in a view:
get_foo_ids = request.GET.get('foo_IDs')
qs_foo = Foo.objects.filter(id__in=get_foo_ids)

So, user generates a queryset of the "Foo" model (with several objects in it), which may contain many objects with a) different FreeModels, and b) precisely matching ManyModels & BarModels. In backend I need to check that all ManyModels and BarModels match in the query. Lets say we have:

qs_foo = <QuerySet [FooObject_1, FooObject_2, FooObject_3]>
#where following must be True:
FooObject_1.must_match_m2m_field.all() == FooObject_2.must_match_m2m_field.all() == FooObject_3.must_match_m2m_field.all()
# and where following must be True also:
FooObject_1.must_match_fk_field == FooObject_2.must_match_fk_field == FooObject_3.must_match_fk_field

for the ForeignKey objects I made following (I think its fair enough):

def check_same_objects(object_list):
        return len(set(object_list)) == 1

check_bars = check_same_objects(qs_foo.values_list('must_match_fk_field', flat=True))

I made this for comparing the lists of objects in the manytomany fields of each object:

def check_same_lists(object_lists):
        for lst in object_lists:
            if set(lst) != set(object_lists[0]):
                return False
        return True


should_match_foos = []
for e in qs_foo:
        should_match_foos.append(e.must_match_m2m_field.all().values_list('id', flat=True))
check_manies = check_same_lists(should_match_foos)

# finally checking both 'must-match-fields':
check_both = all([check_bars, check_manies])

What is the purpose: There is an other model, based on Foo model:

class Fizz(models.Model):
    # model linked to Foo Model, but must persist in DB even if Foo eventually modified or deleted.
    # a pack of Fizz derives from a few 'Foo's...
    foo_relation = models.ManyToMany(Foo, ...)
    # ...
    free_field_ = models.ManyToMany(FreeModel, ...)
    must_match_with_FOO_m2m_field = models.ManyToManyField(ManyModel, ...)
    must_match_with_FOO_fk_field = models.ForeignKey(BarModel, ...)
    # additional DataFields which FOO must not have...

What is the more elegant pythonic/djnago variant of checking if theese two fields match 100% in the whole qs?


Solution

  • I found a shorter solution, which I like more than the original one:

    from collections import Counter
    
    check_manies = check_same_objects(
                     Counter(qs_foo.values_list('must_match_m2m_field', flat=True).values()
                     )
    

    so the first method is enough for all field comparisons (though time efficiency is unclear until now)...