What is the related_name
argument useful for on ManyToManyField
and ForeignKey
fields? For example, given the following code, what is the effect of related_name="maps"
?
class Map(db.Model):
members = models.ManyToManyField(User, related_name="maps",
verbose_name=_('members'))
4
6 Answers
The related_name
attribute specifies the name of the reverse relation from the User
model back to your model.
If you don’t specify a related_name
, Django automatically creates one using the name of your model with the suffix _set
, for instance User.map_set.all()
.
If you do specify, e.g. related_name=maps
on the User
model, User.map_set
will still work, but the User.maps.
syntax is obviously a bit cleaner and less clunky; so for example, if you had a user object current_user
, you could use current_user.maps.all()
to get all instances of your Map
model that have a relation to current_user
.
The Django documentation has more details.
5
Okay, I know this is an old post. But I’m just trying to figure this out – what’s the + trick at the end of the related name? For instance, what happens if I did
related_name='maps+'
in the example above?– Siddif you add the +, django disables the mapping
for OneToOneField default related_name will be small case class name. For example in the given example if members would be OneToOnefield then “User.map” will work.
– anchoif you specify
related_name
, does_set
still work indjango1.11 >
??I use Django 2.1.3 and I can note those are exclusive. Once
related_name
is specified,_set
does not work anymore.
To add to existing answer – related name is a must in case there 2 FKs in the model that point to the same table. For example in case of Bill of material
@with_author
class BOM(models.Model):
name = models.CharField(max_length=200,null=True, blank=True)
description = models.TextField(null=True, blank=True)
tomaterial = models.ForeignKey(Material, related_name="tomaterial")
frommaterial = models.ForeignKey(Material, related_name="frommaterial")
creation_time = models.DateTimeField(auto_now_add=True, blank=True)
quantity = models.DecimalField(max_digits=19, decimal_places=10)
So when you will have to access this data
you only can use related name
bom = material.tomaterial.all().order_by('-creation_time')
It is not working otherwise (at least I was not able to skip the usage of related name in case of 2 FK’s to the same table.)
4
You have to pick a related_name at least for one of them. The other one doesn’t enecssarily require.
related_name
should be plural. Because ForeignKey relations return multiple objects.sorry for the necro posting =) Mesut’s comment has merit. an example of what they are mentioning would be class Employee(models.Model): manager = models.ForeignKey(‘self’, related_name = ‘manages’, on_delete=models.CASCADE, blank=False, null=False) google: “Django Tips #22 Designing Better Models” for more
– boarI just saw this answer, and I’m relatively new to programming. Just wanted to ask that why would someone want to have multiple FKs pointing to the same table? Why not just use the same FK everywhere?
The related_name
argument is also useful if you have more complex related class names. For example, if you have a foreign key relationship:
class UserMapDataFrame(models.Model):
user = models.ForeignKey(User)
In order to access UserMapDataFrame
objects from the related User
, the default call would be User.usermapdataframe_set.all()
, which it is quite difficult to read.
Using the related_name
allows you to specify a simpler or more legible name to get the reverse relation. In this case, if you specify user = models.ForeignKey(User, related_name="map_data")
, the call would then be User.map_data.all()
.
The essentials of your question are as follows.
Since you have Map
and User
models and you have defined ManyToManyField
in Map model, if you want to get access to members of the Map then you have the option of map_instance.members.all()
since you have defined members field.
However, say you want to access all maps a user is a part of then what option do you have.
By default, Django provided you with user_instance.modelname_set.all()
and this will translate to the user.map_set.all()
in this case.
maps is much better than map_set.
related_name provides you an ability to let Django know how you are going to access Map from User model or in general how you can access reverse models which is the whole point in creating ManyToMany fields and using ORM in that sense.
1
Visit revsys.com/tidbits/tips-using-djangos-manytomanyfield for more information about ManyToMany field in Django
The related name parameter is actually an option. If we do not set it, Django
automatically creates the other side of the relation for us. In the case of the Map model,
Django would have created a map_set
attribute, allowing access via m.map_set
in your
example(m being your class instance). The formula Django uses is the name of the model followed by the
string _set
. The related name parameter thus simply overrides Django’s default rather
than providing new behavior.
prefetch_related
use for prefetch data for Many to many and many to one relationship data.
select_related
is to select data from a single value relationship. Both of these are used to fetch data from their relationships from a model. For example, you build a model and a model that has a relationship with other models. When a request comes you will also query for their relationship data and Django has very good mechanisms To access data from their relationship like book.author.name
but when you iterate a list of models for fetching their relationship data Django create each request for every single relationship data. To overcome this we do have prefetchd_related
and selected_related
@DanielRoseman Is it somehow good for performance or good practice to use related_name=’+’ when backwards relation is not necessary?
I’d be curious to know the answer to @lajarre’s question.
@lajarre – I assume that won’t change performance at all. I’ve had to use it once with FeinCMS content types. I personally think it’s good practice to always specify the
related_name
so if you know you won’t use it, I guess it’s a good thing. That’s a personal opinion of course.@3cheesewheel it’s in the docs now: docs.djangoproject.com/en/2.0/ref/models/fields/…
+
means do not create reverse relation