I need let's say Instructors, Students and so on.
Both groups are users, could login etc.
But for example Instructor need many to many relationship with model Subjects.
How to achieve that?
Create a class Instructors that would inherit from Users. Within this class provide the many-to-many relationship. You could also use the profile module to identify the separation.
There are good examples of both here.
EDIT: There is also a good post by James Bennett here.
I wouldn't use inheritors here. Just create models that point to User:
class Instructor(models.Model):
user = models.OneToOneField(User)
# other fields
subjects = models.ManyToManyField('Subject')
class Student(models.Model):
# other fields
user = models.OneToOneField(User)
class Subject(models.Model):
name = models.CharField(max_length=40)
This has the benefit of keeping the common user functionality separate from the Instructor and Student functions. There's really no reason to actually treat Instructors or Students as Users.
You can't point Subject to User-who-is-Instructor model, it can't be expresed in SQL.
What you can do is e.g. to point Subject to User model, making sure in your code that you only create Subject instances for User-s that are members of Instructors group.
Related
I'm building a site where we ask users several personal details (birth date, phone number, address, marital status etc. many more).
Option 1: User model only. Put these personal fields in class User(AbstractUser) model
class User(AbstractUser):
birth_date = ...
phone_number = ...
Option 2: User + UserProfile models: separate login-related data (User) from personal data (UserProfile) like:
class User(AbstractUser):
pass
class UserProfile(models.Model):
user = models.OneToOneField(
User,
to_field="id",
primary_key=True,
on_delete=models.CASCADE,
related_name="user_profile",
)
birth_date = ...
phone_number = ...
Which one is the best practice?
This is subjective, based on each ones opinion/needs. But will go over the technical differences:
Option 1 is easier to use in your code and more efficient as you don't have to do JOINs between tables in order to get all information
Option 2 will make the model look cleaner, with only the most important fields present. This is helpful for data engineers or data analyst who work a lot on SQL visualisation tools
Unless UserProfile has 20+ fields, I would personally go with Option 1.
As always the answer will be "it depends". If your users might have different types of profiles/roles that may require additional set of fields I would go with the second option because it would allow you to have one user model that can combine traits and functionalities of several users. Depending on situation you can call specific method of profile (look for Delegation pattern for more examples).
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.
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
I'm creating a user profile class for my new django website, and I am trying to decide how to represent a user's physical address in my models.
Is it better practice to create a new subclass of model and reference it with a OneToOne key like
class UserProfile(models.Model):
...
address = models.OneToOneField(AddressModel)
...
class AddressModel(models.Model)
street_address = models.CharField(max_length=30)
city = models.CharField(max_length=15)
....
or is it better to create a new address field like
class UserProfile(models.Model):
...
address = AddressField(location_dict)
...
class AddressField(models.Field)
# details go here
...
I generally find it useful to have separate models if the entries might be created independently. For example, if you might end up with a collection of addresses AND a collection of users, not all of which will be linked immediately, then I'd keep them separate.
However, if all addresses in your database will always and immediately be associated with a user, I'd simply add a new field to the model.
Note: some people will tell you that it's wrong and evil to have nullable database columns, and that you should therefore have a separate model if any of your addresses will ever be None. I disagree; while there are often many great reasons to avoid nullable columns, in cases like this I don't find the inconvenience of checking for a null address any more onerous than checking whether the one-to-one model entry exists.
Like Eli said, it's a question of independence. For this particular example, I would make the address a field of UserProfile, but only if you expect to have one address per user. If each user might have multiple addresses (a home address and a vacation address, for example), then I would recommend setting up a model using ForeignKey, which models a Many-To-One relationship.
class UserProfile(models.Model):
...
class AddressModel(models.Model)
user = models.ForeignKey(UserProfile)
street_address = models.CharField(max_length=30)
city = models.CharField(max_length=15)
location = models.CharField(max_length=15) #"Home," "work," "vacation," etc.
Then many AddressModel objects can be created and associated with each UserProfile.
To answer your question, I'd say in general it's probably better to separate out the address as mentioned by other users.
I think the more you learn about database normalization the easier this question is to answer.
This article, Using MySQL, Normalisation, should help you figure out the basics of the "forms" of normalization. BTW, even though it's titled MySQL, it's really very generic for relational databases.
While you don't always need to go through all the normal-forms for all projects, learning about it really helps.
I'm slightly confused about what the "right way" is to design Django models for this particular use case.
I have models called Book, User, Rating. I'm designing an app that let users rate books.
Rating has a many-to-one relationship with user and a many-to-one relationship with Book.
class User(models.Model):
name = models.CharField(max_length=30)
class Book(models.Model):
name = models.CharField(max_length=30)
class Rating(models.Model):
user = models.ForeignKey(User,related_name=ratings)
book = models.ForeignKey(Book,related_name=ratings)
...
With this design, I can't work out how to enforce the rule that a user can only rate each book once. I'm also not sure whether this is the right way to design models for this use case. So if I could get a few pointers in the right direction, it might help me avoid design flaws at this early stage.
Thanks in advance!
You can use the unique_together Meta option on your Rating model: https://docs.djangoproject.com/en/1.3/ref/models/options/#unique-together