How to compare what values two models/querysets share in a view for later display in the template?

I'm trying to compare all the things in ModelOne with ModelTwo, to check which things are or are not in one or the other model, then put this in the view context for display in the template.

class Things(model.Model):
    name = models.CharField()


class ModelOne(models.Model):
    things = models.ManyToManyField(Things)


class ModelTwo(models.Model):
    things = models.ManyToManyField(Things)

How would you do this? Thanks for your time and help, it is appreciated.

one_instance = ModelOne.objects.get(id=one_id)
two_instance = ModelTwo.objects.get(id=two_id)

one_thing_ids = set(one_instance.things.values_list("id", flat=True))
two_thing_ids = set(two_instance.things.values_list("id", flat=True))

shared_thing_ids = one_thing_ids & two_thing_ids
thing_ids_in_one_not_in_two = one_thing_ids - two_thing_ids
thing_ids_in_two_not_in_one = two_thing_ids - one_thing_ids

shared_things = Thing.objects.filter(id__in=shared_thing_ids)

You can then pass shared_things queryset into the template for display.

If your Thing model only has a name field and the names are unique we can simplify a little by altering the model:

class Things(model.Model):
    name = models.CharField(unique=True)

or even:

class Things(model.Model):
    name = models.CharField(primary_key=True, unique=True)

(in this case the db table will not have an id column, it's not needed)

Either way we can then eliminate the extra Thing query at the end:

one_instance = ModelOne.objects.get(id=one_id)
two_instance = ModelTwo.objects.get(id=two_id)

one_thing_names = set(one_instance.things.values_list("name", flat=True))
two_thing_names = set(two_instance.things.values_list("name", flat=True))

shared_thing_names = one_thing_names & two_thing_names
thing_names_in_one_not_in_two = one_thing_names - two_thing_names
thing_names_in_two_not_in_one = two_thing_names - one_thing_names

...and just pass sets of string names into the template.

Back to Top