How to use the 'reverse' of a Django ManyToMany relationship? - django

I'm coming from a Rails background, and am having a bit of trouble making use of the "Association Methods" provided in Django. I have two models (which have been simplified for the sake of brevity), like so:
class User(models.Model):
username = models.CharField(max_length=100, unique=True)
companies = models.ManyToManyField('Company', blank=True)
class Company(models.Model):
name = models.CharField(max_length=255)
According to the Django documentation:
"It doesn't matter which model has the ManyToManyField, but you should only put it in one of the models -- not both.".
So I understand that if I have an instance of a User, called user, I can do:
user.companies
My question is how do I do the reverse? How do I get all users that belong to a Company instance, let's say Company:
company.users # This doesn't work!
What's the convention to do this? The documentation that I've read doesn't really cover this. I need the association to work both ways, so I can't simply move it from one model to the other.

company.user_set.all()
will return a QuerySet of User objects that belong to a particular company. By default you use modelname_set to reverse the relationship, but you can override this be providing a related_name as a parameter when defining the model, i.e.
class User(models.Model):
companies = models.ManyToManyField(Company, ..., related_name="users")
> company.users.all()
here is the relevant documentation

Related

varieties on '*lookups' arguments for the function 'prefetch_related'

I can't figure out the difference between prefetch_related('arg_set') and prefetch_related('arg') .
Sometimes prefetch_related doesn't work when using argument 'arg'even 'arg_set' works.
I've searched through docs.djangoproject.com but, at least, I can't find related document on both pages below.
https://docs.djangoproject.com/en/2.1/ref/models/querysets/ https://docs.djangoproject.com/ja/2.1/ref/contrib/contenttypes/
Could some of you elaborate the difference and when _set is necessary?
And I want to read the official document related to this issue so showing me the reference link is appreciated.
Thank you in advance.
environment:
windows10, python 3.7.2, django 2.1.8, sqlite3, PyCham 2019.1 .
views.py
from django.shortcuts import render
from .models import Article
def index(request):
a = Article.objects.all().select_related('user').prefetch_related('comment_set').order_by('id') # [1]
a = Article.objects.all().select_related('user').prefetch_related('comment').order_by('id') # [2]
return render(request,
'sns/index.html',
{'articles': a})
models.py
from django.db import models
from article_comment_model.settings import AUTH_USER_MODEL
class Article(models.Model):
user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='article_user')
title = models.CharField(max_length=100)
text = models.TextField()
class Comment(models.Model):
user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='comment_user')
article = models.ForeignKey(Article, on_delete=models.CASCADE)
text = models.TextField()
I want to understand the variety of prefetch_related arguments well.
The argument for callig prefetch_related() would be the name of the relation. In your case this would be a reverse ForeignKey relationship. As you can see in the documentation the name of the reverse relationship will be FOO_set where FOO is the model's lowercase name.
Therefore in your example prefetch_related('comment_set') should be correct. If you would specify a related_name like
article = models.ForeignKey(Article, on_delete=models.CASCADE,
related_name='comments')
the related_name will get used instead of FOO_set, therefore prefetch_related('comments') should be valid in this case.
The name of the lookup to use in prefetch_related depends on the answer to a couple of questions:
Is the relation defined on the model you are querying or on the other side of the relationship?
If the relation is defined on the model you are querying (termed "forward relationship" by the Django docs), then the lookup is simply the field name. If the relation is defined at the other end of the relationship ("backward relationship"), then the lookup depends on a second question:
Have you defined a related_name in the other model where the relationship is defined?
If yes, the lookup is the related_name. If there is no related_name, Django uses a default name, which is modelname_set for x-to-many relationships and modelname for x-to-one relationships (both in lower case).
In practical terms, this means the following in your code:
x-to-many relationships:
# no related names defined, using default manager name
Article.objects.prefetch_related('comment_set')
# using related names
User.objects.prefetch_related('article_user', 'comment_user')
x-to-one relationships:
Article.objects.prefetch_related('user')
Comment.objects.prefetch_related('article', 'user')
Using prefetch_related for x-to-one relationships like in the last two examples above is rare. We mostly use select_related as the latter only creates a join in the original query instead of issuing a separate query. However, as you can read towards the end of its documentation, prefetch_related has a few potential advantages. It can:
fetch a filtered queryset
fetch incomplete models (via only and defer)
perform nested prefetching via the Prefetch object

Create a Django's model which can have one of two types

I have a model Client which can be one of two types: PJ or PF. That means that a Client can have the fields of a PJ model or the fields of a PFmodel.
But I'm not sure how I can do it using the Django's models and admin app. I would like to give the user the option to select which type the Client is and then the appropriate fields will be shown to him/her.
Can someone help me with this problem? Should I use some kind of Design Pattern or how should I create my models?
Thanks in advance.
Model PF:
class PF(models.Model):
name = models.CharField(max_length=512)
card = models.IntegerField(unique=True)
Model PJ:
class PJ(models.Model):
ie = models.IntegerField(unique=True, null=True, blank=True)
Model Client:
class Client(models.Model):
type = models.SmallIntegerField(default=0) # 0=PF, 1=PJ
First I'd recommend to look at the commonality between these two models and use inheritance if you can. If a type field is inevitable, I'd recommend using CharField with choices instead.
If the two models are drastically different, I'd recommend separating these two models completely, and call them InternalClient, ExternalClient, however the name would make sense to the data model.

On two related models, which one should contain the definition of the relationship?

First of all, yes: I've read Django's foreign key and many-to-many documentation, but I'm still not 100% clear on how to implement relationships on a practical level, especially regarding the hierarchy of the relationships.
One-to-one
I am aware of how to form one-to-one relationships. However, on a more conceptual level, which model should contain that reference to the other one? Let's say I have a Citizen, and a Passport. Now, it's obvious that one Citizen can only have a single Passport and viceversa, but, ideally, should the Citizen contain a field referencing to his Passport, or should the Passport model contain a reference to the Citizen it belongs to?
Many-to-many
For the sake of simplicity, let's say I have a Person model and a Trip model (Trip as in going out on a trip somewhere). Many Persons can participate in a single Trip. Or in other words: a Person can participate in many Trips and in any single Trip, a lot of Persons can participate. This looks like a many-to-many relationship, but, again, ideally, which model should contain the definition for the relationship, the Person with a trips field or the Trip with a participants field? And why? Does it even make any practical difference?
Thank you.
This depends on your business logic. As a rule of thumb I'd suggest to think about the admin app. How would you like to add new objects?
When adding new objects, how would you like to add related objects?
Let's say you have these models:
Citizen(models.Model):
name = models.CharField()
Passport(models.Model):
number = models.CharField()
citizen = models.OneToOneField('Citizen', related_name='passport')
When adding new passport object, you have the possibility to add new citizen, if it doesn't yet exist. Since this doesn't look very logical to me, I'd change the relation as:
Citizen(models.Model):
# other fields
passport = models.OneToOneField('Passport', related_name='citizen')
Now we can add a new citizen object in the admin and add the related passport object within the same page.
If you use the admin app, this should lead you to more ergonomical design.
EDIT: expand with many-to-many example
Better example for a m2m relation would be StackOverflow - there are questions and tags. A question has many tags, and a tag has many questions. Let's say the models look like this:
Question(models.Model):
title = models.CharField()
body = models.TextField()
author = models.CharField()
tags = models.ManyToManyField('Tag', related_name='questions')
Tag(models.Model):
name = models.CharField()
Why do we put the relation in Question? This should be very logical - when creating a new question you'd like to set the tags for it. When creating a new tag you don't care about any questions associated with it. You can create a tag and later when creating questions, associate them with the tag.
If a tag doesn't exist yet you can add it from the admin, when adding a new question.
I hope this second example is more palpable.
The theory behind this is called database normalization which is a ladder of best practices you should look up if you want to know more about how to structure your data.
The third form tells us that:
"[Every] non-key [attribute] must provide a fact about the key, the whole key, and nothing but the key."
So in the case of ForeignKey fields it should be on the Child model, because it doesn't tell us anything about the parent, but it does tells us what parent the child belongs to.
The mental model that you should have is Parent and Child. Every relationship has two models. So think of one as the Parent model or the Primary model and think of the other one as the Child model or the Secondary model.
NOTE: Always put your relationship field in the CHILD model.
Here is how I would solve your problems:
For the first one, I will have a mental model that Citizen is the Parent and Passport is the child.
class Citizen(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Passport(models.Model):
owner = models.OneToOneField(Citizen)
unique_no = models.CharField(max_length=30, unique=True)
For the second problem, do the same. I would choose Person as the parent model and Trip as the child model.
class Person(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Trip(models.Model):
person = models.ManyToManyField(Person)
info = models.TextField()
If you have sqlitebrowser, you can use that to open your database and check what tables were created according to your models. Then, you will have a clearer idea as to how Django sees your models.

Transform ForeignKey into OneToOne field depending on current user

I have a setup like in the following (simplified) example:
class Pizza(models.Model):
name = models.CharField(max_length=100)
class Favorite(models.Model):
user = models.ForeignKey(User, related_name='favorites')
pizza = models.ForeignKey(Pizza, related_name='favorites')
class Meta:
unique_together = (('user', 'pizza'),)
I know that I can filter the favorites property on a Pizza model instance by the user property, but I'd like to abstract this.
In my application, a user should only have access to its personal Favorite model instances. To ensure this, I find myself having to filter all the time and do a lot of ugly and inefficient stuff.
I want to abstract this so that when a user is logged in, I should be able to access pizza.favorite, instead of pizza.favorites, which is automatically mapped to the current user's Favorite model for this particular Pizza model. Ideally, I should also be able to filter on this property (no possible with the #property annotation). Basically, it should act like the ForeignKey is now a OneToOne field.
Any ideas on how could I achieve this behaviour? I should note that un-authorized users do not concern me. The application does not provide anonymous access, so that edge case can be disregarded.
I am using Django 1.7 and I am also open to using the development version, if that would help.

Django: When extending User, better to use OneToOneField(User) or ForeignKey(User, unique=True)?

I'm finding conflicting information on whether to use OneToOneField(User) or ForeignKey(User, unique=True) when creating a UserProfile model by extending the Django User model.
Is it better to use this?:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
or this?:
class UserProfile(models.Model):
user = models.OneToOneField(User)
The Django Doc specifies OneToOneField, while the Django Book example uses ForeignKey.
James Bennett also has two Blog posts that providing conflicting examples as well:
Extending the User Model
User Registration
In the former post, Bennett provides some reasons why he switched to using ForeignKey instead of OneToOneField, but I don't quite get it, especially when I see other posts that recommend the opposite.
I'm curious to know your preference and why. Or, does it even matter?
The only real reason given in the article is that it can be set up so that the admin page for User will show both the fields in User and UserProfile. This can be replicated with a OneToOneField with a little elbow grease, so unless you're addicted to showing it in the admin page with no work at the cost of a bit of clarity ("We can create multiple profiles per user?! Oh no, wait, it's set unique.") I'd use OneToOneField.
Besides the admin page inlines, other reason for the ForeignKey solution is that it allows you to use the correct, default DB manager when objects are accessed with a reverse relation. Consider example from this subclasses manager snippet. Let's say that the Post class definition from the example looks like this:
class Post(ParentModel):
title = models.CharField(max_length=50)
onetoone = models.ForeignKey(SomeModel, unique=True)
children = ChildManager()
objects = models.Manager()
By calling somemodel_instance.post_set.all()[0], you get the desired subclasses objects of the Post class as indicated by defining the first (default) manager as a ChildManager. On the other hand, with OneToOneField, by calling somemodel_instance.post you get the Post class instance. You can always call somemodel_instance.post.subclass_object and get the same result, but the default manager could do any other sort of tricks and the FK solutions hides them nicely.
If you own and can modify the custom manager code you can use the use_for_related_fields attribute instead of using FK in place of legitimate 1to1 field, but even that can fail because of some not-known to me nuisances of the automatic managers. As far as I remember it will fail in the above example.
Other reason to generally not use the OneToOneField related to reverse relations: when you use reverse relations defined via OneToOneField you get an model instance, contrary to Manager for ForeignKey reverse relation and as a consequence there's always a DB hit. This is costly if you do some generic stuff on reverse relations (via _meta.get_all_related_objects()) and do not know and care if you will use them all or not.