What is the
related_name argument useful for on
ForeignKey fields? For example, given the following code, what is the effect of
class Map(db.Model): members = models.ManyToManyField(User, related_name="maps", verbose_name=_('members'))
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
If you do specify, e.g.
related_name=maps on the
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
The Django documentation has more details.
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.)
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.
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
The essentials of your question are as follows.
Since you have
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.
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
_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