Searching one-to-one-to-many relationship

Question:

I have three models, let’s call them models A, B and C.

A and B share one-to-one relationship, A can exists without B but B must always be linked to A. C has many-to-one relation with B. Or in other words:

class ModelA(models.Model):
  #properties

class ModelB(models.Model):
  a_link = models.OneToOneField(A, on_delete=models.CASCADE, related_name='a_link')
  #rest of the properties

class ModelC(models.Model):
  set = models.ForeignKey(ModelB, on_delete=models.CASCADE)
  user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)

Now, my question is, I want to find all A’s that user has, by checking what Cs they have been tagged in. Can I just do search ModelA.objects.filter(a_link__modelc__user=user) or do I need to first search for Cs in their own query, then select Bs from them and look for their relationship with A?

Asked By: Mandemon

||

Answers:

You can filter with:

ModelA.objects.filter(a_link__modelc__user=user).distinct()

The .distinct() is useful here to avoid that the same ModelA is in the QuerySet multiple times if there are multiple related ModelCs that have as user the user object.

Since the related_name is however the name of the relation in reverse, you might want to rename this to for example:

class ModelA(models.Model):
  #properties

class ModelB(models.Model):
    a_link = models.OneToOneField(
        ModelA,
        on_delete=models.CASCADE,
        related_name='b_object'
    )
    # rest of the properties

class ModelC(models.Model):
    set = models.ForeignKey(ModelB, on_delete=models.CASCADE)
    user = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        blank=True,
        null=True
    )

then the query is thus:

ModelA.objects.filter(b_object__modelc__user=user).distinct()

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Answered By: Willem Van Onsem
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.