【Django】掌握models.py模型文件的使用

2023-09-18 11:17:09

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。



前言

已经有很多人写过相关博客了,我为什么还要写一份呢?这个主要是因为很多文章写的还是很笼统,没法针对使用清晰的进行说明。本博客不是科普如何使用models的,重点关注日常开发中的使用情况,主要介绍类的继承、时间字段、选择字段、文件字段和外键字段。


一、models类继承

models类继承主要依赖Meta.abstract参数,以创建一个全局通用BaseModel为例介绍累的继承。

(一)创建apps文件夹

(二)settings.py文件配置

# 项目根目录
BASE_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(BASE_DIR / "apps"))

(三)新建BaseModel

在app文件夹下新建db.py文件,内容如下:
在这里插入图片描述

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}

(二)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 is_upperclass(self):
        return self.year_in_school in {
            self.YearInSchool.JUNIOR,
            self.YearInSchool.SENIOR,
        }

如果TextChoices枚举被多次使用,还可以抽象为一个单独的包,供django调用。

(三)IntegerChoices枚举

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序列化

四、文件字段FileField

(一)系统默认路径

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_<id>/<filename>
    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)

(三)自定义中间表

六、Django用户表扩展

(一)通过OneToOneField扩展用户表

(二)通过AbstractUser或AbstractBaseUser扩展用户表

1.用户app下modles.py文件

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

2.修改项目settings文件的AUTH_USER_MODEL 配置参数

AUTH_USER_MODEL = 'users.LoginUser'
更多推荐

科技资讯|Vision Pro头显无损音频仅限USB-C AirPods Pro 2耳机

彭博社的马克・古尔曼在最新发布的推文中表示,苹果VisionPro头显的无损音频仅限于USB-CAirPodsPro2耳机。新款采用USB-C的AirPodsPro2升级到了IP54级别(原版不防尘,仅IPX4级抗水),可陪伴用户在恶劣的环境中展开冒险。除此之外,苹果称其将实现具有超低延迟的无损音频,从而通过Apple

Java 学习路线分享 maven 是什么?

Maven是一款基于Java平台的项目管理和整合工具,它将项目的开发和管理过程抽象成一个项目对象模型(POM)。开发人员只需要做一些简单的配置,Maven就可以自动完成项目的编译、测试、打包、发布以及部署等工作。Maven是使用Java语言编写的,因此它和Java一样具有跨平台性,这意味着无论是在Windows,还是在

从淘宝数据分析产品需求(商品销量总销量精准月销)

淘宝数据分析总体来说可以分为商品分析、客户分析、地区分析、时间分析四大维度(参考数据雷达的分析思路)。在这里我重点说商品分析。在淘宝上开店的竞争还是非常激烈的,随便拿出一个单品就有很多竞品存在,所以做起来还是很难的,而想要在众多的竞品中做出来,就需要对竞品数据做分析,那么这个竞品数据在哪里查看呢?下面来了解下吧。淘宝竞

浅谈电动汽车充电桩设计与应用研究

安科瑞华楠摘要:目前,随着我国社会经济的快速发展,我国的各个领域都取得了突破性的发展,尤其是在电动汽车充电桩的设计方法,新型的电动汽车充电桩设计已经广泛的受到了人民群众的青睐与认可,而这种发展前景也是非常可观的,从而使越来越多的人更加重视该行业的发展。但是无论哪一行业的发展,都有利有弊,在电动汽车充电桩设计与应用方面仍

Spring事件机制之ApplicationEvent

博主介绍:✌全网粉丝4W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+MySQL+Vue等前后端

【GAN入门】生成 AI的概念

一、说明GAN是生成对抗网络(GenerativeAdversarialNetwork)的缩写,是一种无监督学习算法,由Goodfellow等人于2014年提出。GAN由一个生成器网络和一个判别器网络组成,通过二者之间的对抗来训练生成器网络生成与真实样本相似的假样本。生成器和判别器互相对抗,不断改善自己的性能。GAN广

Linux的权限管理操作(权限设置chmod、属主chown与所组设置chgrp)

Linux的权限管理权限概述权限介绍身份介绍Owner身份(文件所有者,默认为文档的创建者)Group身份(与文件所有者同组的用户)Others身份(其他人,相对于所有者)Root用户(超级用户)Linux的权限介绍权限设置(chmod)字母形式数字形式注意事项属主与属组设置chown(更改文档的所属用户)chgrp(

Linux如何查看系统时间

文章目录一、使用date命令查看系统时间二、通过/var/log/syslog文件查看系统时间三、通过/proc/uptime文件查看系统运行时间四、通过hwclock命令查看硬件时间五、通过timedatectl命令设置系统时区六、通过NTP协议同步网络时间七、通过ntpstat命令检查NTP同步状态八、使用cal命

RecyclerView滑动时添加缩放效果

最近看到一个动画效果,感觉不错,所以动手试一试我实现的效果基本上是已经实现了头像无限滚动中itemview也伴随缩放效果初步实现基本思路:1、没选择用ViewPager,考虑到特定几张图片的循环显示和扩展我使用recyclerview2、头像重叠效果通过添加ItemDecoration可以实现3、无限循环效果可以重写r

【算法与数据结构】669、LeetCode修剪二叉搜索树

文章目录一、题目二、解法三、完整代码所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。一、题目二、解法思路分析:450、LeetCode删除二叉搜索树中的节点两道题的思路几乎是一样的,只不过终止条件和单层递归逻辑的顺序需要调换,因为本题需要删除的可能不止一个节点,需要先递归到最深

【算法与数据结构】450、LeetCode删除二叉搜索树中的节点

文章目录一、题目二、解法三、完整代码所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。一、题目二、解法思路分析:本题首先要分析删除节点的五种情况:1、没有找到节点2、找到节点左右子树为空左子树为空,右子树不为空右子树为空,左子树不为空左右子树均不为空程序当中我们选择递归法解题,终

热文推荐