2
Django document is still a good place for you to start, and it is really comprehensive for both beginners and professionals. No other shortcut to master it except reading its document and playing with the example.
case a) class A has only one class B instances
UserModel
stands for A
, UserProfile
stands for B
.
Suppose we have a UserModel
, and need one more table to keep the extra information, let’s say UserProfile
. And we allow UserProfile
to be null. then we can use OneToOneField
to bind these two class.
model definition
from django.db import models
class UserModel(models.Model):
name = models.CharField('username', max_length=20)
class UserProfile(models.Model):
nickname = models.CharField('nick name', max_length=50, blank=True, null=True)
# blank tells the validator, this field could be blank, and null tells the db engine, this field could be null.
user = models.OneToOneField(UserModel, blank=True, null=True, on_delete=models.CASCADE)
How to access A from B and vice versa
u = UserModel.objects.get(pk=1)
nickname = u.userprofile.nickname # to access B from A, you can use the model name lowercase name for reference.
profile = UserModel.objects.get(pk=1)
username = profile.user.username # To access A from B, you can use the model name lowercase name for reference.
case b) class A must have one and just one class B instance
UserModel
stands for A
, UserProfile
stands for B
.
For the model definition, it is almost the same as case a). But we need to make sure B is coexistence with A, so we will need to remove Blank
and null
. And we must use post_save
hook to make suer B is also created with A is saved.
Model definition
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_save, pre_save
class UserModel(models.Model):
name = models.CharField('username', max_length=20)
class UserProfile(models.Model):
nickname = models.CharField('nick name', max_length=50)
user = models.OneToOneField(UserModel,on_delete=models.CASCADE)
@receiver(post_save, sender=UserModel)
def create_auth_token(sender, instance=None, created=False, **kwargs):
# This hook is automatically called when the UserModel is created, this is used to make suer UserProfile is also created when UserModel is created.
if created:
UserProfile.objects.create(user=instance)
How to access A from B and vice versa
The same as case a).
case c) class A has many class B instances
Author
stands for A
, Book
stands for B
.
For example, Author
is a model to save the book author information, and one author may write zero or many books, let’s named it to Book
as model. (Suppose only allow one author for each book).
class Author(models.Model):
name = models.CharField('name of the author', max_length=20)
class Book(models.Model):
book_name = models.CharField('name of the book', max_length=50)
author = models.ForeignKey(Author, related_name='books')
How to access A from B and vice versa
# access B from A
author = Author.objects.get(pk=1)
books = author.books
# first book
book_name = books[0].book_name
# access A from B
book = Book.objects.get(pk=1)
author_name = book.author.name
If you allow one book has many authors, then we should use ManyToManyField
instead of ForeignKey
. The Book
model definition changed to this:
class BookAuthor(models.Model):
author = model.ForeignKey(Author)
book = model.ForeignKey(Book)
publish_at = model.DateTimeField(auto_add=True)
class Book(models.Model):
book_name = models.CharField('name of the book', max_length=50)
# through is used to tell django, we have defined another relationship table to bind Author and Book model.
authors = models.ManyToManyField(Author, through='BookAuthor')
How to access A from B and vice versa
author = Author.objects.get(pk=1)
first_book_name = author.book_set.order_by('publish_at')[0].book_name
book = Book.objects.get(pk=1)
author_names = [author.name for author in book.author_set.all()]
case d) class A is a type of class B (so as Restaurant is a type of Business)
Place
stands for B
, Library
and Restaurant
stands for A
.
For example, we defined a generic class Place
, and Library
could be a place, same as Restaurant
.
Model definition
class Place(models.Model):
address = models.CharField('address', max_length=100)
class Library(Place):
num_of_books = models.IntegerField('NO. of books in the library')
class Restaurant(Place):
restaurant_type = models.CharField('The type of the restaurant', max_length=10)
How to use A and B
lib = Library.objects.get(pk=1)
lib.address # get the library address
lib.num_of_books # get the no. of books in this library
rest = Restaurant.objects.get(pk=1)
rest.address # get the restaurant address
rest.restaurant_type # get the restaurant type
For the above case, django will create a Place
table in db, because it is also a model, if you don’t what it to be created, and treat it as Abstract
class as other programming language, you can redefined it as follow:
class Place(models.Model):
address = models.CharField('address', max_length=100)
class Meta:
abstract = True