Django What Is Reverse Relationship

Django What is reverse relationship?

Here is the documentation on related_name

Lets say you have 2 models

class Group(models.Model):
#some attributes

class Profile(models.Model):
group = models.ForeignKey(Group)
#more attributes

Now, from a profile object, you can do profile.group. But if you want the profile objects given the group object, How would you do that? Thats' where related name or the reverse relationship comes in.

Django, by defaults gives you a default related_name which is the ModelName (in lowercase) followed by _set - In this case, It would be profile_set, so group.profile_set.

However, you can override it by specifying a related_name in the ForeignKey field.

class Profile(models.Model):
group = models.ForeignKey(Group, related_name='profiles')
#more attributes

Now, you can access the foreign key as follows:

group.profiles.all()

Django | How to make a reverse Relationship with two models

Rather than using raw SQL joins, in Django you can traverse model relationships in either direction, regardless of how they are represented in the database.

To find all the messages for a given TicketSystem instance:

my_ticket = TicketSystem.objects.get(id=0) # or something
my_ticket_messages = my_ticket.ticketsystem_messages_set.all() # or do other filters here

To find all the messages using a queryset:

TicketSystem_Messages.objects.filter(ticketId=my_ticket)

To find all tickets with more than one message:

from django.db import Count
TicketSystem.objects.annotate(message_count=Count('ticketsystem_messagess')).filter(message_count__gt=1)

How do I write a Django ORM query for the reverse relationship in a one-to-many relationship?

The core issue here is the NameError for articlestat so I will address that first.

As explained in the django documentation your backward relation name by default is defined as FOO_set which in your case means articlestat_set.

If a model has a ForeignKey, instances of the foreign-key model
will have access to a Manager that returns all instances of the
first model. By default, this Manager is named FOO_set,
where FOO is the source model name, lowercased.

If you prefer a different name you can do so by specifying a related_name in your ForeignKey definition e.g.

class ArticleStat(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')
elapsed_time_in_seconds = models.IntegerField(default=0, null=False)

The second issue is how to properly follow relations which is explained quite extensively here which is why I will not go into detail about it in this answer. The gist is that instead of the . operator you want to use __ (double underscore). The same goes for field lookups which you need for comparison in this query.

With both these issues fixed your query should look like this:

Article.objects.filter(articlestat_set__elapsed_time_in_seconds__lte=300)

or with a custom related_name e.g. related_name='articlestats':

Article.objects.filter(articlestats__elapsed_time_in_seconds__lte=300)

Reverse relation in Django

Django uses the related_name of the foreign key to provide a reverse accessor - see the related objects documentation. In your FK from Post_image to Post you have (strangely) called your foreign key "post", therefore you access the images via post.post.all.

Really you should give this a name that actually describe what it does: images would be more suitable. Although you could just as well remove the explicit related_name completely, in which case Django will use the default, which in this case would be post_image_set.

Django reverse relationship (with annotate and filtering)

annotate the count on the Player model and filter on the count:

from django.db.models import Count

Player.objects.filter(
age=25,
matchsup__match__in=matchlist
).annotate(
match_count=Count('matchsup')
).filter(match_count__lt=5)

How to call OneToOneField reverse relationship in template (django)?

As @khadim hussen wrote in the comment you should use the following syntax:

p.user.first_name

Where p is your UserInfo model and p.user is the reference to the OneToOne realationship.

Note that when you don't have a related user with p -> user the value you will return is None.

If you want to show different info than None in your template just can do the following validation:

{% if p.user is not None %}
{{p.user}}
{% else %}
Without User
{% endif %}

But in your views yo will get a RelatedObjectDoesNotExists to ensure in your views that the relationship exists you can make the following validation:

p = UserInfo.objects.first()
if hasattr(p, 'user'):
user = p.user

Other thing that is important is when you have a related_name property as in your example:

user = models.OneToOneField(User, related_name="parent_user", on_delete=models.CASCADE)

So in this case you need to refer to the user property with the related_name.

In a more concrete way you have to do as following:

{{ p.parent_user.first_name }}

One important thing is that if you ar using queryset.filter(...).values() so if you want to load values from other model you can use the following:

queryset.filter(...).values('image','age','bio','user','parent_user__first_name',...)
``
And in your template:
```python
{% p.parent_user__first_name %}

That's it.

How to make reverse relationship query with count in Django

You can work with a .annotate() [Django-doc] and then .filter(…) [Django-doc]:

from django.db.models import Count

Product.objects.annotate(
noptions=Count('product_options')
).filter(
noptions__gt=0
)

Since django-3.2, you can also work with .alias(…) [Django-doc]:

from django.db.models import Count

Product.objects.alias(
noptions=Count('product_options')
).filter(
noptions__gt=0
)


Related Topics



Leave a reply



Submit