Braiano
Braiano

Reputation: 347

Merge two queries in one single query in django

I have a model as follow:

class ModelA(models.Model):
    id = models.CharField()

class ModelB(models.Model):
    name = models.CharField()
    base = models.Boolean(default=False)
    modela = models.ForeignKey(ModelA)

In ModelB we have records as below:

id          name           base        modela
------------------------------------------------
1          solution_base    True        X2ZQ
2          solution_x       False       X2ZQ
3          solution_base    True        ALSB
4          solution_z       False       ALSB
5          solution_base    True        5YET
6          solution_c       False       5YET
7          solution_base    True        PIAT
...        ...              ...         ...

As you can see each record has a base copy of itself that can be distinguished by unique modela foreignkey. All I need, is that by a given normal solution id(example solution_x) I need to query its base equivalent base object (where modela ids are the same). Here what I did so far:

modela_id = ModelB.objects.filter(id=modelb_pk).select_related('modela_id').values_list('modela_id', flat=True)
modelb_solution_base_id = ModelB.objects.filter(modela_id=modela_id[0]).filter(base=True).select_related('modela_id').values_list('id', flat=True)

I guess there should be a solution to merge these two using prefetch_related(Prefetch()) but I have no idea how to use that. Any help will be highly appreciated.

Upvotes: 0

Views: 58

Answers (1)

Daniel W. Steinbrook
Daniel W. Steinbrook

Reputation: 196

I think you're making this a bit more complicated than necessary -- the Django ORM handles much of this for you, thanks to that foreign-key relationship. Given an ID for ModelB, the ID for the other ModelB with the same ModelA but where base=True is just:

 ModelB.objects.get(id=modelb_pk).modela.modelb_set.get(base=True).id

Why does this work?

  1. Because ModelB has a many-to-one relationship with ModelA, we can call .modela on an instance of ModelB to get the corresponding ModelA.
  2. Conversely, given an instance of ModelA, calling .modelb_set returns all ModelB records associated with ModelA.
  3. We can then call .get/.filter on modelb_set just like we would with ModelB.objects.

Upvotes: 1

Related Questions