Add or modify the data model can not be sloppy, the operation of the data should be carefully considered.
Recommended Django data model related packages:
- django-model-utils: use its timestampedmodel
- django-extensions: use its administrative commandsshell_plus, which automatically loads the data model of all installed applications
Split applications with many data models
No more than 5 data models are recommended for each application. If there are too many data models in an application, it means that the application has done too many things and needs to be split.
Choose data model inheritance method carefully
Django supports three inheritance methods:
- Abstract base class
- Multi table inheritance
- surrogate model
Django abstract base class is different from Python abstract base class! They have different purposes and behaviors.
Advantages and disadvantages of various inheritance methods:
|Abstract base class: only inherited child data models can create data tables||It can define common items in abstract parent class to reduce repeated input and the overhead of additional data table and join operation without multi table inheritance||Parent cannot be used alone|
|Multi table inheritance: both parent and child classes create corresponding data tables. There is an implicitOneToOneFieldRelation||Because each data model has a table, the parent and child can be queried separately. At the same time throughparent.childAccess child objects directly from parent||A query on a child table will have a join operation with all its parent tables.Multi table inheritance is not recommended!|
|Proxy model: create data tables only for the original data model||You can create an alias for the original data model and add different Python behaviors||Cannot modify data model item|
How to determine which inheritance method should be used:
- If the amount of overlap is small (only one or two items), inheritance is not needed, but only needs to be defined in both data models
- If there are more duplicates between the two, you should refactor the code and place the same item in an abstract base class
- The proxy model can be useful sometimes, but it’s very different from the other two models
- Multi table inheritance should be avoided because it increases both complexity and performance overhead. Can useOneToOneFieldandForeignKeysInstead.
Data model inheritance practice: timestampedmodel
Add in data modelcreatedandmodifiedTwo timestamp items are a common requirement. You can write a timestampedmodel base class as follows:
# core/models.py from django.db import models class TimeStampedModel(models.Model): """ An abstract base class model that provides self- updating ``created`` and ``modified`` fields. """ created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: abstract = True
Then all data models inherited from the abstract base class will have these two items:
# flavors/models.py from django.db import models from core.models import TimeStampedModel class Flavor(TimeStampedModel): title = models.CharField(max_length=200)
Django has a powerful built-in database modification conduction library calledmigrationsThat is to saydjango.db.migrations。
Suggestions for creating migrations:
- Once an application or data model is created, the initial django.db.migrations should be created for the new data model. In fact, we only needpython manage.py makemigrationsCommand can be completed
- Check the generated migration code before running, especially when complex modifications are involved. Simultaneous usesqlmigrateCommand to verify the actual SQL statements used
- UseMIGRATION_MODULESConfiguration items to manage the migration of third-party applications
- Don’t worry about the number of migrations generated. We can usesquashmigrationsCommand to merge it
Deployment and management migrations:
- Before deployment, check whether the migrations can be rolled back.
- If there are millions of data in the table, the data of this magnitude should be tested on the staging server. Migrations on a real database can take much longer than expected!
If MySQL is used:
- It must be backed up before schema changes are involved. MySQL does not provide transaction support for schema modification, so rollback is not possible
- If possible, items should be placed in theread-onlyPattern
- Schema changes to a large number of tables can take a lot of time. Not seconds, not minutes, but hours!
Django data model design
Standardize the database
A data model should not contain data that has been saved in other data models.
Caching should be done before denormalization
Only when it is absolutely necessary can we carry out inverse normalization
When to use null and blank
|Data item type||Set null = true||Set blank = true|
|CharField, TextField, SlugField, EmailField, CommaSeparatedIntegerField, UUIDField||Do not set this. The tradition of Django is to save the null value as an empty string, and the obtained null or empty value is parsed as an empty string||Can be set. If you allow its corresponding form item to accept null values.|
|FileField, ImageField||Do not set this. Django will justMEDIA_ROOTThe path to the file is saved in charfield, so the rule is the same as above||You can set the rules like charfield|
|BooleanField||Do not set this. Do not use this field, use nullboolfield||Don’t set it like this|
|Integerfield, floatfield, decimalfield, durationfield, etc||If you allow null to be stored in the database, you can set it as follows||If you allow its corresponding form component to accept null values, you can set this, and set null = true at the same time|
|Datefieldfield, DateField, timefield, etc||If you allow null to be stored in the database, you can set it as follows||If you allow the corresponding form component to accept null values, or use theauto_now、auto_now_addThis can be set. Set null = true at the same time|
|ForeignKey, ManyToManyField, OneToOneField||You can set it like this||You can set it like this|
|GenericIPAddressField||You can set it like this||You can set it like this|
|IPAddressField||This type is not recommended and is obsolete in Django 1.7||This type is not recommended|
When to use binaryfield
This type is added in Django 1.8 to hold raw binary data, orbytes。 Filter, exclude, or other SQL operations cannot be performed on this type of item. But it works when:
- Message pack content
- Sensor raw data
- Compressed data. For example, sentry is saved as BLOB data, but Base64 encoding is required due to historical reasons
Binary data strings can be large, which slows down the database. In this case, you should save the content in a file, and then use filefield to reference it.
Never provide file services through binaryfield ：
- Reading and writing to the database is slower than the file system
- Your database will become larger and smaller, and thus lower and lower performance
- At this time, the access file needs to go through Django application layer and database layer.
Try to avoid using generic association models.field.genericforeignkey
Using genericforeignkey will make the foreign key not subject to integrity constraints. There are the following problems:
- Query speed will be reduced due to lack of index between models
- The data table may refer to a nonexistent record, and the data may be damaged
The advantage is that without integrity constraints, a data item can be associated with different types of records. Most of them are used in voiting, tagging and ratings.
have access toForeignKeyandManyToManyTo achieveGenericForeignKeyIt not only ensures the integrity of the data, but also improves the performance.
- Try to avoid using common associations andGenericForeignKey
- If general association is needed, try whether it can be solved by adjusting data model design or using new PostgreSQL items
- If you have to, it’s best to use an off the shelf third-party application
PostgreSQL specific items: when to use null and blank
|Data item type||Set null = true||Set blank = true|
|ArrayField||Can set||Can set|
|HStoreField||Can set||Can set|
|Integerrangefield, bigintegerrangefield and floatrangefield||Can be set. If you want to store null in the database||Can be set. If you allow its corresponding form component to accept null values. Set null = true at the same time|
|Datatimerangefield and daterangefield||Ditto||Ditto|
Data model_meta API
_metaOnly used internally before Django 1.8. The interface is now public.
- Get the list of items in the data model
- Gets the class (or inheritance chain or other derived information) of a specific item in the data model
- You can make sure that the way you get this information will not change in future Django releases
- A introspective tool for creating a Django data model
- Create a custom form library
- Create a tool similar to admin to edit or interact with data in the Django data model
- Create a visualization or analysis library, such as analyzing information about items starting with “foo”
Data model manager
The data model manager is used to restrict all possible data records of a data model class. Django provides a default manager for each data model class.
We can define our own data model manager, such as:
from django.db import models from django.utils import timezone class PublishedManager(models.Manager): use_for_related_fields = True def published(self, **kwargs): return self.filter(pub_date__lte=timezone.now(), **kwargs) class FlavorReview(models.Model): review = models.CharField(max_length=255) pub_date = models.DateTimeField() # add our custom model manager objects = PublishedManager()
At this time, if we want to find out the number of all comments first and then the number of comments that have been published, we can do this:
>>> from reviews.models import FlavorReview >>> FlavorReview.objects.count() 35 >>> FlavorReview.objects.published().count() 31
For the default manager that replaces the data model, take special care:
- First, when using data model inheritance, the subclass of abstract base class will receive the data model manager of its parent class, but the subclass using multi table inheritance will not
- Second, the first data model manager that applies to a data model class is treated as the default manager. This is very different from the normal Python mode, which will make the returned query result different from the expected one
Therefore, theobjects = models.Manager()Before all custom data model managers.
Understanding fat data model
fat modelsThe concept is: do not scatter the data related code in views and templates, but encapsulate these logic in methods, class methods, properties and even manager methods of the data model. This way, all views and tasks can reuse the code.
The disadvantage of this method: it will make the data model more and more code, so it is difficult to maintain and understand.
Therefore, when the amount of code in the data model becomes very large and complex, the relevant repeated code should be separated and placed in theModel BehaviororHelper FunctionsMedium.
Behaviors of data model, also known as mixins
Behaviors of data model follow the idea of combination and encapsulation by using mixins.
Related resources: use even to reduce duplicate code
Stateless helper functions
The logic is placed in the set of utility functions to separate them, making testing easier. The disadvantage: because these functions are stateless, all parameters need to be passed.
Reference: two scoops of Django: Best Practices for Django 1.8