原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。
已经有很多人写过相关博客了,我为什么还要写一份呢?这个主要是因为很多文章写的还是很笼统,没法针对使用清晰的进行说明。本博客不是科普如何使用models的,重点关注日常开发中的使用情况,主要介绍类的继承、时间字段、选择字段、文件字段和外键字段。
models类继承主要依赖Meta.abstract参数,以创建一个全局通用BaseModel为例介绍累的继承。
# 项目根目录
BASE_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(BASE_DIR / "apps"))
from django.contrib.gis.db import models
class BaseModel(models.Model):
"""模型抽象基类"""
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
is_delete = models.BooleanField(default=False, verbose_name="删除标记")
class Meta:
# 说明是一个抽象模型类,此句必须有,否则迁移会失败
abstract = True
from db import BaseModel
class CartItem(BaseModel):
id = models.AutoField(primary_key=True)
class Meta:
verbose_name = '购物车'
verbose_name_plural = '购物车'
之前写过一篇关于python中如何使用时间的一篇博客《【Python】时间标准库处理》,当时就考虑到django在使用时,涉及到时间格式的转化和使用。
class BaseModel(models.Model):
"""模型抽象基类"""
create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
from django.utils import timezone
from db import BaseModel
class CartItem(BaseModel):
id = models.AutoField(primary_key=True)
create_time = models.DateTimeField('创建时间(BJ)', default=timezone.now, blank=True)
class Meta:
verbose_name = '购物车'
verbose_name_plural = '购物车'
transfer_time = models.DateTimeField('星地数传时间', null=True, blank=True, help_text='星地数传时间')
常用的选择字段是models.CharField,还可以使用models.IntegerField。下面我们看看都是如何使用。
models.CharField是最常见的,也是使用最多的
from django.db import models
class Student(models.Model):
FRESHMAN = "FR"
SOPHOMORE = "SO"
JUNIOR = "JR"
SENIOR = "SR"
GRADUATE = "GR"
YEAR_IN_SCHOOL_CHOICES = {
FRESHMAN: "Freshman",
SOPHOMORE: "Sophomore",
JUNIOR: "Junior",
SENIOR: "Senior",
GRADUATE: "Graduate",
}
year_in_school = models.CharField(
max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in {self.JUNIOR, self.SENIOR}
from django.utils.translation import gettext_lazy as _
class Student(models.Model):
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,
default=YearInSchool.FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in {
self.YearInSchool.JUNIOR,
self.YearInSchool.SENIOR,
}
如果TextChoices枚举被多次使用,还可以抽象为一个单独的包,供django调用。
class Card(models.Model):
class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4
suit = models.IntegerField(choices=Suit)
如果使用的是基础的选择方式,django提供了默认的序列化方法 get_year_in_school_dispaly()可供调用。如果选择了TextChoices或者IntegerChoices,需要自己写序列化方法。
TextChoices示例如下:
from django.utils.translation import gettext_lazy as _
class Student(models.Model):
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,
default=YearInSchool.FRESHMAN,
)
def get_year_in_school_name(self):
return YearInSchool(self.year_in_school).name
def get_year_in_school_value(self):
return YearInSchool(self.year_in_school).value
def get_year_in_school_label(self):
return YearInSchool(self.year_in_school).label
以上示例中的name是FRESHMAN ,value是"FR",label是_(“Freshman”),常用的方式为get_year_in_school_label。参考drf序列化
class MyModel(models.Model):
# file will be uploaded to MEDIA_ROOT/uploads
upload = models.FileField(upload_to="uploads/")
# or...
# file will be saved to MEDIA_ROOT/uploads/2015/01/30
upload = models.FileField(upload_to="uploads/%Y/%m/%d/")
上述示例是系统默认方式,文件最终将被保存至 MEDIA_ROOT 路径下
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_/
return "user_{0}/{1}".format(instance.user.id, filename)
class MyModel(models.Model):
upload = models.FileField(upload_to=user_directory_path)
类型 | 描述 |
---|---|
instance | 模型的实例,其中 FileField 定义。更具体地说,这是附加当前文件的特定实例。 |
filename | 最初提供给文件的文件名。在确定最终目的地路径时,可以考虑,也可以不考虑。 |
需要制定storage参数,国内常用的是阿里云、腾讯云、华为云等厂商的存储服务,我们需要在settings.py文件中自定义DEFAULT_FILE_STORAGE 参数。比如django使用阿里云的oss存储需要用django-aliyun-oss2-storage库。
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
"Manufacturer",
on_delete=models.CASCADE,
)
class Manufacturer(models.Model):
# ...
pass
class MissionData(models.Model):
bill = models.ForeignKey(Bill, verbose_name='消费记录', on_delete=models.SET_NULL, null=True, blank=True)
class LoginUser(AbstractUser):
"""用户表"""
uuid = models.UUIDField(default=uuid.uuid1, unique=True, editable=False)
name = models.CharField(verbose_name='真实姓名', max_length=30, null=True, blank=True)
phone = models.CharField(verbose_name='手机号', max_length=11, null=True, blank=True)
roles = models.ManyToManyField(verbose_name='拥有的所有角色', to='Roles')
class Meta:
verbose_name = '系统用户'
verbose_name_plural = '系统用户'
app_label = 'users'
def __str__(self):
return self.username
AUTH_USER_MODEL = 'users.LoginUser'