四、Django模型

Model

Model (模型) 简而言之即数据模型,是一个Django应用的核心。模型不是数据本身(比如数据表里的数据), 而是抽象的描述数据的构成和逻辑关系。

每个Django的模型(model)实际上是个类,继承了models.Model。每个Model应该包括属性(字段),关系(比如单对单,单对多和多对多)和方法。当你定义好Model模型后,Django的接口会自动帮你在数据库生成相应的数据表(table)。

模型的组成

一个标准的Django模型分别由模型字段、META选项和方法三部分组成。我们接下来对各部分进行详细介绍。Django官方编码规范建议按如下方式排列:

  • 定义的模型字段:包括基础字段和关系字段
  • 自定义的Manager方法:改变模型
  • class Meta选项: 包括排序、索引等等(可选)。
  • def str():定义单个模型实例对象的名字(可选)。
  • def save():重写save方法(可选)。
  • def get_absolute_url():为单个模型实例对象生成独一无二的url(可选)
  • 其它自定义的方法

模型的字段

models.Model提供的常用模型字段包括基础字段和关系字段。

基础字段

CharField()

python 复制代码
from django.db import models

class MyModel(models.Model):
    my_char_field = models.CharField(max_length=100)
  • max_length:必填参数,用于限定字段可以存储的字符的最大长度。
  • blank:布尔值,默认为 False。如果设置为 True,则该字段允许为空。
  • null:布尔值,默认为 False。如果设置为 True,则 Django 在数据库中使用 NULL 来存储空值。
  • default:字段的默认值。
  • editable:布尔值,默认为 True。如果设置为 False,这个字段将不会在 Django 管理界面或者任何 ModelForm 中显示。
  • help_text:用于在表单字段旁边显示额外的帮助文本。
  • verbose_name:为字段设置一个人类可读的名字。

TextField()

python 复制代码
from django.db import models

class MyModel(models.Model):
    my_text_field = models.TextField()
  • 适合大量文本,max_length = xxx选项可选。
  • blank:布尔值,默认为 False。如果设置为 True,则该字段允许为空。
  • null:布尔值,默认为 False。如果设置为 True,则 Django 在数据库中使用 NULL 来存储空值。
  • default:字段的默认值。
  • editable:布尔值,默认为 True。如果设置为 False,这个字段将不会在 Django 管理界面或者任何 ModelForm 中显示。
  • help_text:用于在表单字段旁边显示额外的帮助文本。
  • verbose_name:为字段设置一个人类可读的名字。

DateField() 和DateTimeField()

python 复制代码
from django.db import models

class MyModel(models.Model):
    my_date_field = models.DateField()
  • DateField 用于存储日期,不包括时间

  • 可通过default=xx选项设置默认日期和时间。

  • 对于DateTimeField: default=timezone.now - 先要from django.utils import timezone

  • 如果希望自动记录一次修改日期(modified),可以设置: auto_now=True

  • 如果希望自动记录创建日期(created),可以设置auto_now_add=True

  • auto_now_add:布尔值,默认为 False。如果设置为 True,则当对象首次被创建时,字段会被设置为当前日期。

  • auto_now:布尔值,默认为 False。如果设置为 True,则每次对象保存时,字段会被设置为当前日期。

  • blank:布尔值,默认为 False。如果设置为 True,则该字段允许为空。

  • null:布尔值,默认为 False。如果设置为 True,则 Django 在数据库中使用 NULL 来存储空值。

  • default:字段的默认值。这可以是一个日期值,或者一个返回日期值的可调用对象。

  • editable:布尔值,默认为 True。如果设置为 False,这个字段将不会在 Django 管理界面或者任何 ModelForm 中显示。

  • help_text:用于在表单字段旁边显示额外的帮助文本。

  • verbose_name:为字段设置一个人类可读的名字。

EmailField()

  • 如不是必填项,可设置blank = True和default = '。一般Email用于用户名应该是唯一的,建议设置unique = True
  • max_length:用于限定字段可以存储的字符的最大长度。默认值为 254,这是因为这是标准电子邮件地址的最大长度。
  • blank:布尔值,默认为 False。如果设置为 True,则该字段允许为空。
  • null:布尔值,默认为 False。如果设置为 True,则 Django 在数据库中使用 NULL 来存储空值。
  • default:字段的默认值。
  • editable:布尔值,默认为 True。如果设置为 False,这个字段将不会在 Django 管理界面或者任何 ModelForm 中显示。
  • help_text:用于在表单字段旁边显示额外的帮助文本。
  • verbose_name:为字段设置一个人类可读的名字

IntegerField()

  • IntegerField 是一个用于存储整数的字段。
  • 它适用于那些需要存储整数的地方,比如年龄、数量等。
  • 在数据库层面,通常对应于整数类型。

SlugField()

  • SlugField 是一个用于存储"slug"的字符串字段,通常用于URLs。
  • "Slug"是一个短标签,通常只包含字母、数字、下划线或连字符,用于提高URL的可读性。
  • 它默认最大长度为50个字符,并且可以用max_length参数自定义。
  • 通常,SlugField会有一个unique_for_date参数,用于确保在给定日期范围内slug的唯一性。

URLField()

  • URLField 是一个用于存储URL的字符串字段。
  • 它默认最大长度为200个字符,也可以用max_length参数自定义。
  • 在数据库层面,它通常对应于一个VARCHAR字段。

BooleanField()

  • BooleanField 是一个用于存储布尔值(True/False)的字段。
  • 它通常用于表示"是/否"或"开/关"这样的二值状态。
  • 在数据库层面,通常对应于一个布尔类型。

FileField()

FileField(upload_to=None, max_length=100) - 文件字段

  • upload_to = "/some folder/":上传文件夹路径

  • max_length = xxxx:文件最大长度

ImageField()

ImageField (upload_to=None, max_length=100,)- 图片字段

  • upload_to = "/some folder/": 指定上传图片路径

关系字段

OneToOneField()

OneToOneField(to, on_delete=xxx, options) - 单对单关系

  • to必需指向其他模型

  • 必需指定on_delete选项(删除选项): i.e, "on_delete =

  • models.CASCADE" or "on_delete = models.SET_NULL" .

  • 可以设置 "related_name = xxx" 便于反向查询。

ForeignKey()

ForeignKey(to, on_delete=xxx, options) - 单对多关系

  • to必需指向其他模型.

  • 必需指定on_delete选项(删除选项): i.e, "on_delete = models.CASCADE" or "on_delete = models.SET_NULL" .

  • 可以设置"default = xxx" or "null = True" ;

  • 如果有必要,可以设置 "limit_choices_to = ",

  • 可以设置 "related_name = xxx" 便于反向查询。

ManyToManyField()

ManyToManyField(to, options) - 多对多关系

  • to 必需指向其他模型,比如 User or 'self' .
  • 设置 "symmetrical = False " 表示多对多关系不是对称的,比如A关注B不代表B关注A
  • 设置 "through = 'intermediary model' " 如果需要建立中间模型来搜集更多信息。
  • 可以设置 "related_name = xxx" 便于反向查询。

对于OneToOneField和ForeignKey, on_delete选项和related_name是两个非常重要的设置,前者决定了了关联外键删除方式,后者决定了模型反向查询的名字。

on_delete删除选项

Django提供了如下几种关联外键删除选项, 可以根据实际需求使用。

  • CASCADE:级联删除。当你删除publisher记录时,与之关联的所有都会被删除。
  • PROTECT: 保护模式。如果有外键关联,就不允许删除,删除的时候会抛出ProtectedError错误,除非先把关联了外键的记录删除掉。
  • SET_NULL: 置空模式。删除的时候,外键字段会被设置为空。
  • SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值。
  • SET(): 自定义一个值。
  • DO_NOTHING:什么也不做。删除不报任何错,外键值依然保留,但是无法用这个外键去做查询
  • related_name 选项用于指定从相关模型反向引用时的名称。这个选项允许你从一个关系的"另一边"引用对象,而不必直接通过模型的字段名。
python 复制代码
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')

在这个例子中,Book 模型有一个指向 Author 模型的 ForeignKey。通过设置 related_name='books',我们可以在 Author 实例上使用 books 属性来获取所有与之相关的 Book 实例。

重要特性

如果没有指定 related_name,Django 会自动创建一个默认的名称,格式为 <model_name>_set,其中 <model_name> 是关系的另一端的模型的小写名称(例如,如果 Book 模型有一个指向 Author 的 ForeignKey,默认的 related_name 将是 book_set)。

如果你的模型被用于多个 ForeignKey 或 ManyToManyField,为每个关系指定一个唯一的 related_name 是一个好的实践,这样可以避免命名冲突。

如果你不希望为关系创建反向名称,可以将 related_name 设置为 '+' 或者 None(在 Django 1.9 及以后版本中)。

示例

python 复制代码
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='publications')

class Article(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='articles')

在这个例子中,Author 可以通过 publications 属性获取其所有的 Book 实例,通过 articles 属性获取其所有的 Article 实例。

使用 related_name:

python 复制代码
author = Author.objects.get(name="Jane Doe")
author_books = author.publications.all()  # 获取所有与Jane Doe相关的书籍
author_articles = author.articles.all()   # 获取所有与Jane Doe相关的文章

如果不使用 related_name:

python 复制代码
author_books = Book.objects.filter(author=author)  # 使用默认的related_name
author_articles = Article.objects.filter(author=author)  # 使用默认的related_name

模型的META选项

在 Django 中,每个模型都有一个内部类叫做 Meta,它用于包含模型的元数据,即关于模型自身的配置信息。这些元数据不会直接转换为数据库字段,但它们会影响模型的行为,尤其是在数据库层面和 Django 管理界面中的表现。

以下是一些常用的 Meta 选项及其用途:

abstract

类型:布尔值

默认值:False

用途:如果设置为 True,则模型会被视为抽象基类,不会创建对应的数据库表。

app_label

类型:字符串

用途:指定模型所属的应用的名称。通常不需要设置,因为 Django 会自动确定。

db_table

类型:字符串

用途:指定模型在数据库中对应的表名。如果不设置,Django 会自动生成表名,格式为 <app_label>_<model_name>。

db_tablespace

类型:字符串

用途:指定模型使用的数据库表空间。如果数据库支持表空间,这个选项可以用来指定模型表应该使用的表空间。

get_latest_by

类型:字符串或字段名

用途:指定一个字段名,通常是日期或时间字段,以便使用 Model.objects.latest() 方法时按照该字段排序获取最新记录。

managed

类型:布尔值

默认值:True

用途:如果设置为 False,Django 不会为该模型创建或删除数据库表。这在模型映射到预先存在的数据库表或是在非数据库数据源上时很有用。

order_with_respect_to

类型:字段名

用途:用于多对多关系,允许对象根据指定的字段进行排序。

ordering

类型:字符串或字段列表

用途:指定对象默认的排序方式。例如,['name'] 表示按照 name 字段的升序排序。

permissions

类型:二元组列表

用途:为模型添加额外的权限。每个元组应该包含两个元素:权限代码和人类可读的权限名称。

proxy

类型:布尔值

默认值:False

用途:如果设置为 True,则模型会被视为代理模型。它将继承其父模型的字段,但不会创建新的数据库表。

unique_together

类型:字段名列表的列表

用途:指定字段组合的唯一性约束。例如,unique_together = [('username', 'email')] 表示 username 和 email 的组合必须是唯一的。

verbose_name

类型:字符串

用途:为模型设置一个人类可读的单数名称。

verbose_name_plural

类型:字符串

用途:为模型的复数名称设置一个人类可读的名称。

以下是一个包含 Meta 类的模型示例:

python 复制代码
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    class Meta:
        ordering = ['last_name']
        verbose_name_plural = "people"

模型的方法

在 Django 中,模型不仅仅是数据库表的简单映射;它们也是具有行为的 Python 对象。你可以为模型添加自定义的方法来执行各种操作,比如计算字段值、处理相关对象,或者执行任何其他需要的业务逻辑。

以下是一些常见类型的模型方法及其用途:

自定义管理器方法

虽然不是直接在模型上定义的,但管理器方法是模型中经常使用的方法。它们允许你对查询集进行自定义操作。

python 复制代码
from django.db import models

class BookManager(models.Manager):
    def title_count(self, keyword):
        return self.filter(title__icontains=keyword).count()

class Book(models.Model):
    title = models.CharField(max_length=100)
    objects = BookManager()

# 使用自定义管理器方法
book_count = Book.objects.title_count('django')

自定义实例方法

这些方法通常用于处理单个模型实例。

python 复制代码
class Author(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Book)

# book_count 方法返回与特定作者相关的书籍数量。
    def book_count(self):
        return self.books.count()

自定义类方法

类方法与实例方法不同,因为它们不需要特定的实例来调用。它们可以用来返回查询集或者执行与特定实例无关的操作。

python 复制代码
class Book(models.Model):
    title = models.CharField(max_length=100)
    published_date = models.DateField()

#recent_books 类方法返回最近30天内发布的书籍。
    @classmethod
    def recent_books(cls):
        return cls.objects.filter(published_date__gte=datetime.now() - timedelta(days=30))

自定义静态方法

静态方法不依赖于类或实例的状态。它们用于执行一些不访问任何属性或方法的操作。

python 复制代码
class Book(models.Model):
    title = models.CharField(max_length=100)
#is_valid_title 静态方法检查给定的标题是否有效。
    @staticmethod
    def is_valid_title(title):
        return len(title) > 0

保存和删除钩子

Django 提供了 save 和 delete 方法的钩子,你可以在这些方法中添加自定义逻辑。

python 复制代码
class Book(models.Model):
    title = models.CharField(max_length=100)

    def save(self, *args, **kwargs):
        do_something_before_save()
        super(Book, self).save(*args, **kwargs)
        do_something_after_save()

    def delete(self, *args, **kwargs):
        do_something_before_delete()
        super(Book, self).delete(*args, **kwargs)
        do_something_after_delete()

以下是一个综合了上述方法的模型示例:

python 复制代码
from django.db import models
from datetime import datetime, timedelta

class Author(models.Model):
    name = models.CharField(max_length=100)

    def get_books(self):
        return self.book_set.all()

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    published_date = models.DateField()

    def was_published_recently(self):
        return self.published_date >= datetime.now() - timedelta(days=30)

    @classmethod
    def get_recent_books(cls):
        return cls.objects.filter(published_date__gte=datetime.now() - timedelta(days=30))

    def save(self, *args, **kwargs):
        if not self.title:
            raise ValueError("Book must have a title.")
        super(Book, self).save(*args, **kwargs)
相关推荐
databook9 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar10 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户83562907805110 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_10 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机17 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机18 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机18 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机18 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i18 小时前
drf初步梳理
python·django
每日AI新事件18 小时前
python的异步函数
python