如何正确的使用 django,成为你的开发利器

304 阅读3分钟

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=Trueblank=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_namereleated_query_name

BookAuthor 俩个表查询关系如下:

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.datetimeUUID)。例如可以使用 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