Model
模型定义属于是 django 的基础,如果一开始设计不太好的话,接下来的开发乃至后续维护都会面临一些问题。
以下是 django 第三方的 Model 工具:
- django-model-utils
- django-extensions
Model 设计
建立模型之前,我们建议了解数据库规范化(如三大范式)。
- 确保每列保持原子性(数据不可再分)
- 确保每列完全依赖于主键(唯一性)
- 确保属性不依赖于其他非主属性(独立性)
Timestamp
每条记录我们都应该创建 该记录的 创建时间 和 修改时间。
from django.db import models
class TimeStampedModel(models.Model):
"""
abstract base class, 提供创建时间和修改时间两个通用的field
"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
null 和 blank
模型字段可以定义 null=True
和 blank=True
何时使用也是比较关键的,如下。
我们应该尽量避免使用 null=True
。
Field 类型 | 设置 null=True | 设置blank=True |
---|---|---|
CharField TextField SlugField EmailField | 不要设置,django规定储存空字符串来代表空值, 当从数据库中读取NULL或空值时都为空字符串 | 可以设置,设置后允许接受widget中为空值(即不填写), 储存到数据库时空值变为空字符串 |
FileField ImageField | 不要设置,django实际储存的是路径的字符串 | 可以设置 |
IntegerField FloatField DecimalField | 可以设置,如果希望在数据库中能储存NULL | 可以设置,设置后允许接受widget中为空值(即不填写), 设置为True时必须同时设置null=True |
DateTimeField DateField TimeField | 可以设置,如果希望在数据库中能储存NULL | 可以设置,设置后允许接受widget中为空值(即不填写), 设置为True时必须同时设置null=True |
BooleanField | 不要设置,因为有NullBooleanField代替 | 不要设置 |
ForeignKey ManyToManyField OneToOneField | 可以设置,如果希望在数据库中能储存NULL | 可以设置,设置后允许接受widget中为空值(即不填写) |
模型关系
善于使用 releated_name
和 releated_query_name
Book
和 Author
俩个表查询关系如下:
from django.db import models
class Book(models.Model):
author = models.ForeignKey('Author', releated_name='books', releated_query_name='book')
class Author(models.Model):
pass
查询关系
author = Author.objects.first()
print(author.books.all())
authors = Author.objects.filter(book__pk__in=[1])
print(authors)
枚举
使用 django 枚举
from django.db import models
from django.utils.translation import gettext_lazy as _
class Student(models.Model):
# 如果枚举值为 Text
class YearInSchool(models.TextChoices):
FRESHMAN = 'FR', _('Freshman')
SOPHOMORE = 'SO', _('Sophomore')
JUNIOR = 'JR', _('Junior')
SENIOR = 'SR', _('Senior')
GRADUATE = 'GR', _('Graduate')
year_in_school = models.CharField(
max_length=2,
choices=YearInSchool.choices,
default=YearInSchool.FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in {
self.YearInSchool.JUNIOR,
self.YearInSchool.SENIOR,
}
由于枚举值需要为整数的情况极为常见,Django 提供了一个 IntegerChoices 类。例如:
from django.db import models
class Card(models.Model):
class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4
suit = models.IntegerField(choices=Suit.choices)
我们在判断的时候,例如:
Good:
card = Card.objects.last()
card.suit == Suit.DIAMOND
>>> False
card.suit
>>> 3
card.suit == Suit.HEART
>>> True
Bad:
card = Card.objects.last()
card.suit == 2
>>> False
card.suit
>>> 3
card.suit == 3
>>> True
card.suit == Suit.HEART.value
>>> True
JsonField
JsonField
可以提高应用程序的性能,因为可以将多个相关数据存储在单个字段中,从而减少数据库查询的次数。
那么将如何设置比较好呢?
JSONEncoder
子类序列化标准JSON序列化器不支持的数据类型(例如: datetime.datetime
或UUID
)。例如可以使用 DjangoJSONEncoder
from django.db imoprt models
from django.core.serializers.json import DjangoJSONEncoder
class Order(Model):
...
contact = models.JsonField(default=dict, blank=True, encoder=DjangoJSONEncoder)
...
时区配置
这里推荐使用
# 时区
TIME_ZONE = 'Asia/Tokyo'
# 是否存储使用 utc 时间
USE_TZ = True