django笔记《模型和数据库一》

news2024/9/20 22:30:32

文章目录

  • 1 前言
  • 2 创建一个demo项目
    • 2.1 修改配置文件
  • 3 模型
    • 3.1 主键
    • 3.2 django 内置字段类型
    • 3.3 自定义字段类型
    • 3.4 django字段选项
    • 3.5 字段备注名
    • 3.5 META
    • 3.6 关联关系
      • 3.6.1 多对一关系
      • 3.6.2 多对多关系
      • 3.6.3 一对一关系
    • 3.7 字段命名限制
    • 3.8 模型属性:Model.objects
    • 3.9 模型方法
      • 3.9.1 重写django定义的模型方法:如save() delete()
    • 3.10 模型继承
      • 3.10.1 通过抽象基类继承
      • 3.10.2 多表继承
      • 3.10.3 代理模型
  • 4 增、删、改
    • 4.1 新增数据
      • 4.1.1 单表增加数据
      • 4.1.2 验证数据
      • 4.1.3 多对一数据增加
      • 4.1.3 多对多数据增加
    • 4.2 删除数据
    • 4.3 改变数据
  • 5 查
    • 5.1 获取全部记录
    • 5.2 过滤器检索对象
      • 5.2.1 filter(**kwargs)
      • 5.2.2 exclude(**kwargs)
      • 5.2.3 详解filter、exclude、get中的关键字参数
        • (1) exact(完全匹配)
        • (2) iexact(不区分大小写匹配)
        • (3) contains(区分大小写的包含)
        • (4) icontains(不区分大小写的包含)
        • (5) in(判断字段值是否在一个可迭代对象中)
        • (6) gt(大于)
        • (7) gte(大于等于)
        • (8) lt(小于)
        • (9) lte(小于等于)
        • (10) startswith(区分大小写的开头)
        • (11)istartswith(不区分大小写的开头)
        • (12)endswith(区分大小写的结尾)
        • (13)iendswith(不区分大小写的结尾)
        • (14)range(范围测试,包含开始和结尾)
        • (15) 以下是时间相关的查询字段:
        • (16) date (从日期时间字段取出日期值)
        • (17) year(从日期时间字段取出年份)
        • (18) iso_year(精确的 ISO 8601 周号年份匹配)
        • (19) month(精确的月份匹配1到12)
        • (20) day(精确的日期匹配1到31)
        • (21) week
        • (22) week_day
        • (23) iso_week_day
        • (24) quarter(季度)
        • (25) time(取datetime中的时间部分)
        • (26) hour(取datetime中的小时部分)
        • (27) minute(取datetime中的分钟部分)
        • (28) second(取datetime中的秒部分)
        • (29)isnull(取datetime中的秒部分)
        • (30)regex(区分大小写的正则表达式匹配)
        • (31)iregex(不区分大小写的正则表达式匹配)
    • 5.3 跨表查询
      • 5.3.1 多对一跨表查询
      • 5.3.3 多对多跨表查询

1 前言

任何软件系统都离不开对数据表的增删改查,django提供了ORM框架来操作数据表,当让也支持原生SQL查询

ORM框架中的对应关系大概如下

ORM数据库表
数据库的一张表
类变量数据库表中的字段
实例对象数据库中的一条记录

通过操作ORM类的实例对象,操作数据库中的表。

2 创建一个demo项目

  • 创建一个虚拟环境
E:\coding\django_deme_project>pipenv install --python 3.10  
Creating a virtualenv for this project...
Pipfile: E:\coding\django_deme_project\Pipfile
Using D:/Envs/Py3.10.1/python.exe (3.10.1) to create virtualenv...
[==  ] Creating virtual environment...created virtual environment CPython3.10.1.final.0-64 in 984ms
  creator CPython3Windows(dest=E:\coding\django_deme_project\.venv, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\Administrator\AppData\Local\pypa\virtualenv)
    added seed packages: pip==22.3.1, setuptools==65.6.3, wheel==0.38.4
  activators BashActivator,BatchActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

Successfully created virtual environment!
Virtualenv location: E:\coding\django_deme_project\.venv
Creating a Pipfile for this project...
Pipfile.lock not found, creating...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Updated Pipfile.lock (e4eef2)!
Installing dependencies from Pipfile.lock (e4eef2)...
  ================================ 0/0 - 00:00:00
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run.
  • 进入虚拟环境
E:\coding\django_deme_project>pipenv shell
Launching subshell in virtual environment...
Microsoft Windows [版本 10.0.19044.1320]
(c) Microsoft Corporation。保留所有权利。
  • 安装两个必要的包 django 和 pymysql 其他包随用随装
(.venv) E:\coding\django_deme_project>pip install django
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting django
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/21/26/28895838228c46ece278d764720995d5a51e4bce7d02d2a54e70f59108e1/Django-4.1.4-py3-none-any.whl (8.1 MB)
Collecting asgiref<4,>=3.5.2
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/8f/29/38d10a47b322a77b2d12c2b79c789f52956f733cb701d4d5157c76b5f238/asgiref-3.6.0-py3-none-any.whl (23 kB)
Collecting sqlparse>=0.2.2
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/97/d3/31dd2c3e48fc2060819f4acb0686248250a0f2326356306b38a42e059144/sqlparse-0.4.3-py3-none-any.whl (42 kB)
Collecting tzdata
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/fa/5e/f99a7df3ae2079211d31ec23b1d34380c7870c26e99159f6e422dcbab538/tzdata-2022.7-py2.py3-none-any.whl (340 kB)
Installing collected packages: tzdata, sqlparse, asgiref, django
Successfully installed asgiref-3.6.0 django-4.1.4 sqlparse-0.4.3 tzdata-2022.7

(.venv) E:\coding\django_deme_project>pip install pymysql
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pymysql
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/4f/52/a115fe175028b058df353c5a3d5290b71514a83f67078a6482cff24d6137/PyMySQL-1.0.2-py3-none-any.whl (43 kB)
Installing collected packages: pymysql
Successfully installed pymysql-1.0.2
(.venv) E:\coding\django_deme_project>django-admin startproject demo01

(.venv) E:\coding\django_deme_project>cd demo01

(.venv) E:\coding\django_deme_project\demo01>django-admin startapp app01

虽然django的ORM对于数据库的类型没有要求,但是mysql是主流数据库,所以使用mysql数据库

  • 创建好的项目目录
│─manage.py  
├─app01
│  │  admin.py
│  │  apps.py
│  │  models.py
│  │  tests.py
│  │  views.py
│  │  __init__.py
│  │
│  └─migrations
│          __init__.py
│
└─demo01
        asgi.py
        settings.py
        urls.py
        wsgi.py
        __init__.py

2.1 修改配置文件

修改dem01/settings.py:

  • 配置中文和时区
LANGUAGE_CODE = 'zh-Hans'  # 改语言为中文
TIME_ZONE = 'Asia/Shanghai'  # 改时区为上海
USE_TZ = False  # 为False时,存到数据库的时间不使用标准时区

  • 配置数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djangodemo01',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}
  • 在demo01/_ _ init _ _.py中安装依赖
import pymysql

pymysql.install_as_MySQLdb()

至此demo项目搭建完成了。

下面开始进入正题:

3 模型

模型准确且唯一的描述了数据。它包含您储存的数据的重要字段和行为。一般来说,每一个模型都映射一张数据库表。
每个模型都是一个 Python 的类,这些类继承 django.db.models.Model
模型类的每个属性都相当于一个数据库的字段。

3.1 主键

每个模型都需要拥有一个设置了 primary_key=True 的字段(无论是显式的设置还是 Django 自动设置)。
默认情况下,Django 给每个模型一个自动递增的主键,其类型在 AppConfig.default_auto_field 中指定,或者在 DEFAULT_AUTO_FIELD 配置中全局指定
在这里插入图片描述

如果你想自己指定主键, 在你想要设置为主键的字段上设置参数 primary_key=True。如果 Django 看到你显式地设置了 Field.primary_key,将不会自动在表(模型)中添加 id 列。

3.2 django 内置字段类型

字段类型描述备注
AutoField一个 IntegerField,根据可用的 ID 自动递增。你通常不需要直接使用它;如果你没有指定,主键字段会自动添加到你的模型中。
BigAutoField一个 64 位整数,与 AutoField 很相似,但保证适合 1 到 9223372036854775807 的数字。
BigIntegerField一个 64 位的整数,和 IntegerField 很像,只是它保证适合从 -9223372036854775808 到 9223372036854775807 的数字。该字段的默认表单部件是一个 NumberInput。
BinaryField一个用于存储原始二进制数据的字段。可以指定为 bytes、bytearray 或 memoryview。
BooleanField一个 true/false 字段。该字段的默认表单部件是 CheckboxInput,或者如果 null=True 则是 NullBooleanSelect。当 Field.default 没有定义时,BooleanField 的默认值是 None。
CharField一个字符串字段,适用于小到大的字符串。对于大量的文本,使用 TextField。该字段的默认表单部件是一个 TextInput。最常用的字段类型
DateField一个日期,在 Python 中用一个 datetime.date 实例表示DateField.auto_now(每次保存对象时,自动将该字段设置为现在。对于“最后修改”的时间戳很有用。请注意,当前日期 总是 被使用,而不仅仅是一个你可以覆盖的默认值。只有在调用 Model.save() 时,该字段才会自动更新。当以其他方式对其他字段进行更新时,如 QuerySet.update(),该字段不会被更新,尽管你可以在这样的更新中为该字段指定一个自定义值。) DateField.auto_now_add(当第一次创建对象时,自动将该字段设置为现在。对创建时间戳很有用。请注意,当前日期是 始终 使用的;它不是一个你可以覆盖的默认值。因此,即使你在创建对象时为该字段设置了一个值,它也会被忽略。如果你想修改这个字段,可以设置以下内容来代替 auto_now_add=True :)
DateTimeField一个日期和时间,在 Python 中用一个 datetime.datetime 实例表示。与 DateField 一样,使用相同的额外参数。
DecimalField一个固定精度的十进制数,在 Python 中用一个 Decimal 实例来表示。它使用 DecimalValidator 验证输入
EmailField一个 CharField,使用 EmailValidator 来检查该值是否为有效的电子邮件地址。
DurationField一个用于存储时间段的字段——在 Python 中用 timedelta 建模
FileField一个文件上传字段primary_key 参数不支持,如果使用,会引起错误。
FilePathField一个 CharField,其选择仅限于文件系统中某个目录下的文件名。有一些特殊的参数,其中第一个参数是 必须的。一个目录的绝对文件系统路径
FloatField在 Python 中用一个 float 实例表示的浮点数。
GenericIPAddressFieldIPv4 或 IPv6 地址,字符串格式(如 192.0.2.30 或 2a02:42fe::4 )。该字段的默认表单部件是一个 TextInput。
ImageField继承 FileField 的所有属性和方法,但也验证上传的对象是有效的图像。需要 Pillow 库。
IntegerField一个整数。从 -2147483648 到 2147483647 的值在 Django 支持的所有数据库中都是安全的。
JSONField一个用于存储 JSON 编码数据的字段。在 Python 中,数据以其 Python 本地格式表示:字典、列表、字符串、数字、布尔值和 None。
PositiveBigIntegerField0 到 9223372036854775807
PositiveIntegerField0 到 2147483647
PositiveSmallIntegerField0 到 32767
SlugFieldSlug 是一个报纸术语。slug 是一个简短的标签,只包含字母、数字、下划线或连字符。它们一般用于 URL 中。
SmallAutoField就像一个 AutoField,1 到 32767
SmallIntegerField就像一个 IntegerField,从 -32768 到 32767 的值
TextField一个大的文本字段。该字段的默认表单部件是一个 Textarea。
TimeField一个时间,在 Python 中用 datetime.time 实例表示。接受与 DateField 相同的自动填充选项。
URLFieldURL 的 CharField,由 URLValidator 验证。
UUIDField一个用于存储通用唯一标识符的字段。使用 Python 的 UUID 类。当在 PostgreSQL 上使用时,它存储在一个 uuid 的数据类型中,否则存储在一个 char(32) 中。

3.3 自定义字段类型

留白

3.4 django字段选项

以下选型对所有字段都有效,且是可选的

字段选型描述备注
null如果是 True, Django 将在数据库中存储空值为 NULL。默认为 False。null参数只影响数据库,如果希望在表单中允许空值,设置blank属性为True
blank如果是 True ,该字段允许为空。默认为 False 。null纯属数据库相关,blank与验证相关,blank=False则该字段为必填字段
choices一个 sequence 本身由正好两个项目的迭代项组成(例如 [(A,B),(A,B)…]get_filed_display()来获取实际值
db_column这个字段要使用的数据库列名。如果没有给出列名,Django 将使用字段名。
db_index如果是 True,将为该字段创建数据库索引。
db_tablespace如果这个字段有索引,那么要为这个字段的索引使用的 数据库表空间 的名称。默认是项目的 DEFAULT_INDEX_TABLESPACE 设置(如果有设置),或者是模型的 db_tablespace (如果有)。如果后端不支持索引的表空间,则忽略此选项。
default该字段的默认值。可以是一个值或者是个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。
editable如果是 False,该字段将不会在管理或任何其他 ModelForm 中显示。在 模型验证 中也会跳过。默认为 True。
error_messageserror_messages 参数可以让你覆盖该字段引发的默认消息。传入一个与你想覆盖的错误信息相匹配的键值的字典。
help_text额外的“帮助”文本,随表单控件一同显示。即便你的字段未用于表单,它对于生成文档也是很有用的。
primary_key如果设置为 True ,将该字段设置为该模型的主键。primary_key=True 意味着 null=False 和 unique=True。一个对象只允许有一个主键。主键字段是只读的。如果您改变了现有对象的主键值,然后将其保存,则会在旧对象旁边创建一个新对象。
unique如果设置为 True,这个字段必须在整个表中保持值唯一。
unique_for_date将其设置为 DateField 或 DateTimeField 的名称,要求该字段的日期字段值是唯一的。
unique_for_month
unique_for_year
verbose_name字段的一个人类可读名称,如果没有给定详细名称,Django 会使用字段的属性名自动创建,并将下划线转换为空格。
validators要为该字段运行的验证器列表

3.5 字段备注名

除了 ForeignKey, ManyToManyField 和 OneToOneField,任何字段类型都接收一个可选的位置参数 verbose_name,如果未指定该参数值, Django 会自动使用字段的属性名作为该参数值,并且把下划线转换为空格。

first_name = models.CharField("person's first name", max_length=30)

verbose_name = person’s first name

first_name = models.CharField(max_length=30)

verbose_name = first name

惯例是不将 verbose_name 的首字母大写,必要时 Django 会自动把首字母转换为大写。

3.5 META

class School(models.Model):
    name = models.CharField(max_length=32, help_text='学校名称', unique=True)
    address = models.CharField(max_length=32, help_text='学校地址')

    class META:
        abstract = True   #这个模型将是一个抽象基类。
        app_label = 'myapp'  # 如果在 INSTALLED_APPS 中定义了一个应用程序之外的模型,它必须声明它属于哪个应用程序
        base_manager_name = 'objects'  # 管理器的属性名,例如,'objects',用于模型的 _base_manager。
        db_table = 'school_table' # 数据库表名称,默认是“应用名_模型名小写"
        db_tablespace = '' # 此模型要使用的 数据库表空间 名称。如果有设置的话,默认是项目的 DEFAULT_TABLESPACE 配置。如果后端不支持表空间,则忽略此选项。
        default_manager_name = '' # 模型的 _default_manager 管理器名称。
        default_related_name = '' # 从相关对象到这个对象的关系默认使用的名称。默认为 _set。这个选项还可以设置 related_query_name。
        get_latest_by = '' #模型中的字段名或字段名列表,通常是 DateField,DateTimeField 或 IntegerField。这指定了在你的模型中使用的默认字段 Manager 的 last() 和 earliest() 方法。
        managed = True  # True:migrate管理  False:不被migrate管理
        order_with_respect_to = ''  # 使该对象可以根据给定字段(通常是 ForeignKey )进行排序。这可以用来使相关对象相对于父对象可排序。例如,如果一个 Answer 与一个 Question 对象相关,而一个问题有多个答案,并且答案的顺序很重要
        ordering = ['name'] # 对象的默认排序,用于获取对象列表时,-:表示降序  ?:表示随机
        permissions = [('can_deliver_pizzas', 'Can deliver pizzas')] # 创建此对象时要输入权限表的额外权限。为每个模型自动创建添加、更改、删除和查看权限
        default_permissions = ('add', 'change', 'delete', 'view') #
        proxy = True  # 作为另一个模型子类的模型将被视为 代理模型。
        #required_db_features = '' # 当前连接应具备的数据库特征列表,以便在迁移阶段考虑模型。
        # required_db_vendor = ''  # 支持的数据库厂商
        select_on_save = False # 默认False
        indexes = [] # 你想在模型上定义的 indexes 的列表
        unique_together = ['name', 'address']  # 一组字段名,合起来必须是唯一的:
        index_together = ['name', 'address'] # 一组字段名,合在一起,是有索引的:
        constraints = [] #你想在模型上定义的 约束 列表
        verbose_name = 'school'  # 对象的可读名称,单数:
        verbose_name_plural = 'schools' # 对象的复数名称

3.6 关联关系

显然,关系型数据库的强大之处在于各表之间的关联关系。 Django 提供了定义三种最常见的数据库关联关系的方法:多对一,多对多,一对一。

3.6.1 多对一关系

一个学校可以有多个学生,一个学成理论上只能上一所公立学校。
在学校和学生这个关系中,学校是“一方” , 学生是“多方”
对于多对一的关系,应该在多方创建外键,关联到一方,外键通过models.ForeignKey()配置在多方的类属性中,models.ForeignKey中需要两个必填字段,分别是to和on_delete

  • to 表示关联的模型

    # 如果两个模型都属于同一个app, 那么直接写类名就可以
    class School(models.Model):
    	...
    	# 一方
    class Student(models.Model):
    	...
    	# 多方
    	# 注意这种写法一定要把一方的模型类写到上面,否则会报错,因为python代码是从上向下解释的。
    	school = models.ForeignKey(to=School, on_delete=models.CASCADE)
    # 如果两个模型不属于同一个app,但是也存在一对多的关系
    school = models.ForeignKey(to='app_name.model_name', on_delete=models.CASCADE)
    
  • on_delete 表示关联的对象被删除后,有外键约束的记录应该怎么处理
    在这里插入图片描述
    在这里插入图片描述
    如果清华大学被删除了,那下面的三个学生应该怎么处理就是on_delete选型考虑的事情

    • models.CASCADE

    级联删除。Django 模拟了 SQL 约束 ON DELETE CASCADE 的行为,也删除了包含 ForeignKey 的对象。

    • models.PROTECT

    通过引发 ProtectedError,即 django.db.IntegrityError 的子类,防止删除被引用对象。

    • models.RESTRICT

    通过引发 RestrictedError ( django.db.IntegrityError 的一个子类)来防止删除被引用的对象。与 PROTECT 不同的是,如果被引用的对象也引用了一个在同一操作中被删除的不同对象,但通过 CASCADE 关系,则允许删除被引用的对象。

    class Artist(models.Model):
        name = models.CharField(max_length=10)
    
    class Album(models.Model):
        artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    
    class Song(models.Model):
        artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
        album = models.ForeignKey(Album, on_delete=models.RESTRICT)
    Artist 可以被删除,即使这意味着删除被 Song 引用的 Album,因为 Song 也通过级联关系引用 Artist 本身。例如:
    >>> artist_one = Artist.objects.create(name='artist one')
    >>> artist_two = Artist.objects.create(name='artist two')
    >>> album_one = Album.objects.create(artist=artist_one)
    >>> album_two = Album.objects.create(artist=artist_two)
    >>> song_one = Song.objects.create(artist=artist_one, album=album_one)
    >>> song_two = Song.objects.create(artist=artist_one, album=album_two)
    >>> album_one.delete()
    # Raises RestrictedError.
    >>> artist_two.delete()
    # Raises RestrictedError.
    >>> artist_one.delete()
    (4, {'Song': 2, 'Album': 1, 'Artist': 1})
    
    
    • SET_NULL

    设置 ForeignKey 为空;只有当 null 为 True 时,才有可能。

    • SET_DEFAULT

    将 ForeignKey 设置为默认值,必须为 ForeignKey 设置一个默认值。

    • SET()
    from django.conf import settings
    from django.contrib.auth import get_user_model
    from django.db import models
    
    def get_sentinel_user():
        return get_user_model().objects.get_or_create(username='deleted')[0]
    
    class MyModel(models.Model):
        user = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.SET(get_sentinel_user),
        )
    
    • DO_NOTHING

    不采取任何行动。如果你的数据库后端强制执行引用完整性,这将导致一个 IntegrityError 除非你手动添加一个 SQL ON DELETE 约束条件到数据库字段。

模型创建代码

class School(models.Model):
    name = models.CharField(max_length=32, help_text='学校名称', unique=True)
    address = models.CharField(max_length=32, help_text='学校地址')

    class Meta:
        base_manager_name = 'objects'  # 管理器的属性名,例如,'objects',用于模型的 _base_manager。
        db_table = 'school_table'  # 数据库表名称,默认是“应用名_模型名小写"
        default_related_name = '_set'  # 从相关对象到这个对象的关系默认使用的名称。默认为 _set。这个选项还可以设置 related_query_name。
        get_latest_by = ''  # 模型中的字段名或字段名列表,通常是 DateField,DateTimeField 或 IntegerField。这指定了在你的模型中使用的默认字段 Manager 的 last() 和 earliest() 方法。
        managed = True  # True:migrate管理  False:不被migrate管理
        ordering = ['name']  # 对象的默认排序,用于获取对象列表时,-:表示降序  ?:表示随机
        unique_together = ['name', 'address']  # 一组字段名,合起来必须是唯一的:
        verbose_name = 'school'  # 对象的可读名称,单数:
        verbose_name_plural = 'schools'  # 对象的复数名称


class Student(models.Model):
    """
    学生类
    """
    name = models.CharField(max_length=32, help_text='学生名称', unique=True)
    age = models.PositiveSmallIntegerField(default=10)
    grade = models.PositiveSmallIntegerField(null=True, blank=True)
    school = models.ForeignKey(to='app01.School', on_delete=models.SET_NULL, related_name='students', null=True)
  • 自关联一对多

    class Student(models.Model):
        """
        学生类
        """
        name = models.CharField(max_length=32, help_text='学生名称', unique=True)
        age = models.PositiveSmallIntegerField(default=10)
        grade = models.PositiveSmallIntegerField(null=True, blank=True)
        school = models.ForeignKey(to='app01.School', on_delete=models.SET_NULL, related_name='students', null=True, blank=True)
        classmate = models.ForeignKey(to='self',on_delete=models.SET_NULL, related_name='classmates', null=True, blank=True) # 自关联多对一
    

3.6.2 多对多关系

  • models.ManyToManyField()
    ManyToManyField 接受一组额外的参数——都是可选的——控制关系如何运作。

    • related_name

    与 ForeignKey.related_name 相同。

    • related_query_name

    与 ForeignKey.related_query_name 相同。

    • symmetrical

    仅在自身上定义多对多字段关系时。考虑以下模型

    from django.db import models
    
    class Person(models.Model):
        friends = models.ManyToManyField("self")
    
    

    当 Django 处理这个模型时,它识别出它本身有一个 ManyToManyField,因此,它没有给 Person 类添加 person_set 属性。相反, ManyToManyField 被认为是对称的,也就是说,如果我是你的朋友,那么你就是我的朋友。
    如果你不想让 self 的多对多关系对称,可以将 symmetrical 设置为 False。这样会强制 Django 添加反向关系的描述符,允许 ManyToManyField 关系是非对称的。

    • through

    Django 会自动生成一个表来管理多对多关系。但是,如果你想手动指定中间表,你可以使用 through 选项来指定代表你要使用的中间表的 Django 模型。
    当使用多对多关联两个表时:中间表格式
    id :关系的主键。
    表1_id :表1 id。
    表2_id :表2 id。
    当使用多对多关联一张表时,也就是自关联多对多的情况
    id :关系的主键。
    from_id :表 id。
    to_id :表 id。

    • through_fields
      只有当指定了一个自定义的中间模型时才会使用,Django 通常会决定使用中间模型的哪些字段来自动建立多对多的关系。然而,考虑以下模型:

      from django.db import models
      
      class Person(models.Model):
          name = models.CharField(max_length=50)
      
      class Group(models.Model):
          name = models.CharField(max_length=128)
          members = models.ManyToManyField(
              Person,
              through='Membership',
              through_fields=('group', 'person'),
          )
      
      class Membership(models.Model):
          group = models.ForeignKey(Group, on_delete=models.CASCADE)
          person = models.ForeignKey(Person, on_delete=models.CASCADE)
          inviter = models.ForeignKey(
              Person,
              on_delete=models.CASCADE,
              related_name="membership_invites",
          )
          invite_reason = models.CharField(max_length=64)
      

      中间表Membership中有两个与Person表的外键,分别是person和inviter,这种情况会导致django在建立多对多关系的时候不知道使用哪个外键,所以需要在ManyToMany中设置through_fields,through_fields是一个包含两个元素的元组,这两个元素分别为中间表中指向两个表的外键属性,比如上个例子中的(person, group)

    • db_table

    要创建的用于存储多对多数据的表的名称。如果没有提供这个表名,Django 将根据以下表名创建一个默认表名:定义关系的模型表和字段本身的名称。

    • db_constraint

    控制是否应该在数据库中为中间表的外键创建约束。默认值是 True,不能同时设置through和db_constraint

    • swappable

    控制迁移框架的反应,如果这个 ManyToManyField 指向一个可交换的模型。如果它是 True ——默认值——那么如果 ManyToManyField 指向的模型与 settings.AUTH_USER_MODEL 的当前值相匹配(或其他可交换模型配置),关系将被存储在迁移中,使用对配置的引用,而不是直接对模型的引用。
    只有当你确定你的模型应该总是指向换入的模型时,你才想把它覆盖为 False,例如,如果它是一个专门为你的自定义用户模型设计的配置文件模型。
    如果不确定,就保留它在默认为 True 的状态。

  • 不通过中间表创建多对多关系

class Student(models.Model):
    """
    学生类
    """
    name = models.CharField(max_length=32, help_text='学生名称', unique=True)
    age = models.PositiveSmallIntegerField(default=10)
    grade = models.PositiveSmallIntegerField(null=True, blank=True)
    school = models.ForeignKey(to='app01.School', on_delete=models.SET_NULL, related_name='students', null=True, blank=True)
    classmate = models.ForeignKey(to='self',on_delete=models.SET_NULL, related_name='classmates', null=True, blank=True)

    def __str__(self):
        return f"{self.school.name}--->{self.name}"


class Teacher(models.Model):
    name = models.CharField(max_length=32, help_text='老师名字', unique=True)
    students = models.ManyToManyField(Student)

    class Meta:
        pass
  • 通过中间表创建多对多关系
class Student(models.Model):
    """
    学生类
    """
    name = models.CharField(max_length=32, help_text='学生名称', unique=True)
    age = models.PositiveSmallIntegerField(default=10)
    grade = models.PositiveSmallIntegerField(null=True, blank=True)
    school = models.ForeignKey(to='app01.School', on_delete=models.SET_NULL, related_name='students', null=True, blank=True)
    classmate = models.ForeignKey(to='self',on_delete=models.SET_NULL, related_name='classmates', null=True, blank=True)

    def __str__(self):
        return f"{self.school.name}--->{self.name}"


class Teacher(models.Model):
    name = models.CharField(max_length=32, help_text='老师名字', unique=True)
    students = models.ManyToManyField(Student, through='Student2Teacher')

    class Meta:
        pass


class Student2Teacher(models.Model):
    """
    老师学生中间表
    """
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
    data_joined = models.DateField()

中间表中可以添加其他字段,用于记录一条对应关系,比如老师A何时开始教的学生A,这个时间记录在data_joined字段中。

3.6.3 一对一关系

一对一关系一般用于将两个表合并为一个宽表,通过外键进行关联,同时给外键设置成unique=True。
如果没有为 OneToOneField 指定 related_name 参数,Django 将使用当前模型的小写名作为默认值。

  • 实例-扩展auth_user表

    from django.conf import settings
    from django.db import models
    
    class MySpecialUser(models.Model):
        user = models.OneToOneField(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
        )
        supervisor = models.OneToOneField(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
            related_name='supervisor_of',
    
    >>> user = User.objects.get(pk=1)
    >>> hasattr(user, 'myspecialuser')
    True
    >>> hasattr(user, 'supervisor_of')
    True
    
    

3.7 字段命名限制

  • 字段名称不能是python关键字
  • 字段名称不能包含连续的两个下划线,不能以下划线结尾

3.8 模型属性:Model.objects

模型当中最重要的属性是Manager(后面简称模型管理类),模型管理类是模型和数据库查询操作之间的接口,执行查询操作必须使用模型管理类,如果没有在模型Meta类中定义base_manager_name 属性,默认的模型管理类属性名为:objects,除非极特殊情况,否则不会改变这个属性名。

模型管理类只能通过模型类访问,不能通过实例访问

3.9 模型方法

模型方法定义在模型内,模型方法提供“行级”操作能力,模型管理类(Manager:Model.objects)提供“表级”操作能力。

  • __str__()

一个 Python 的“魔法方法”,返回值友好地展示了一个对象。

  • get_absolute_url()

该方法告诉 Django 如何计算一个对象的 URL。Django 在后台接口使用此方法,或任意时间它需要计算一个对象的 URL。
任何需要一个唯一 URL 的对象需要定义此方法。

3.9.1 重写django定义的模型方法:如save() delete()

  • 重写save()方法,选择性保存

    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        def save(self, *args, **kwargs):
            if self.name == "Yoko Ono's blog":
                return # Yoko shall never have her own blog!
            else:
                super().save(*args, **kwargs)  # Call the "real" save() method.
    

3.10 模型继承

3.10.1 通过抽象基类继承

在模型类的Meta类中定义abstract属性为True。
其他模型可以做为抽象类的子类,这时子类会同步抽象类的所有属性,但是django不会创建抽象类的表。

class BaseModel(models.Model):
    create_time = models.DateTimeField(auto_now_add=datetime.datetime.now)  # 创建时时间
    update_time = models.DateTimeField(auto_now=datetime.datetime.now)  # 更新时时间

    creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)

    class Meta:
        abstract = True


class Blog(BaseModel):
    """
    博客类
    """
    title = models.CharField(max_length=128, unique=True)

    def __str__(self):
        return f'{self.title}'

上面这两个类第一个是抽象模型类,第二个是继承抽象模型类的博客类。

做数据库迁移:

python manage.py makemigrations
python manage.py migrate 

查看数据库中的数据表:

在这里插入图片描述

查看app01_blog表结构:

在这里插入图片描述

在模型类blog中继承了抽象基类中定义的类属性。

3.10.2 多表继承

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

Place 的所有字段均在 Restaurant 中可用,虽然数据分别存在不同的表中。所有,以下操作均可:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

若有一个 Place 同时也是 Restaurant,你可以通过小写的模型名将 Place 对象转为 Restaurant 对象。

>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>

3.10.3 代理模型

from django.db import models

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

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

MyPerson 类与父类 Person 操作同一张数据表。特别提醒, Person 的实例能通过 MyPerson 访问,反之亦然。

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

你也可以用代理模型定义模型的另一种不同的默认排序方法。你也许不期望总对 “Person” 进行排序,但是在使用代理时,总是依据 “last_name” 属性进行排序:

class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True

现在,普通的 Person 查询结果不会被排序,但 OrderdPerson 查询接轨会按 last_name 排序。

4 增、删、改

4.1 新增数据

4.1.1 单表增加数据

class School(models.Model):
    name = models.CharField(max_length=32, help_text='学校名称', unique=True)
    address = models.CharField(max_length=32, help_text='学校地址')

用这个模型做为测试模型:

python manage.py shell 进入终端操作界面:

PS E:\coding\django_deme_project\demo01> python .\manage.py shell
Python 3.10.1 (tags/v3.10.1:2cd268a, Dec  6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)

  • 方式一:
>>> from app01.models import School 
>>> School 
<class 'app01.models.School'>
>>> s1 = School(name="北京大学", address="北京市")
>>> s1.save() 
  • 方式二:
>>> School.objects.create(name="浙江大学",address="杭州")
<School: School object (3)>

4.1.2 验证数据

重写save()方法即可

使用下面三个模型进行测试
教室模型、学生模型、老师模型
一个教室有多个学生,一个学生理论上只有一个教室
一个学生可以有多位老师,一个老师也可以同时教多个学生

4.1.3 多对一数据增加

class ClassRoom(models.Model):
    name_choices = (
        (1, "初级班"),
        (2, "中级班"),
        (3, "高级班"),
        (4, "特级班"),
    )
    name = models.PositiveSmallIntegerField(choices=name_choices, default=1)


class Student(models.Model):
    name = models.CharField(max_length=32)
    age = models.PositiveSmallIntegerField(default=12)
    class_room = models.ForeignKey(to='app02.ClassRoom', on_delete=models.SET_NULL, null=True, blank=True,
                                   related_name='students')


class Teacher(models.Model):
    name = models.CharField(max_length=32)
    students = models.ManyToManyField(Student)

执行数据库迁移命令

python manage.py makemigrations app02
python manage.py migrate app02

执行完成之后在数据库中在这里插入图片描述
会创建4张表格,分别是:

  • 插入教室表:

    >>> cr1 = ClassRoom(name=1) 
    >>> cr2 = ClassRoom(name=2) 
    >>> cr3 = ClassRoom(name=3) 
    >>> cr4 = ClassRoom(name=4) 
    >>> cr1.save()              
    >>> cr2.save() 
    >>> cr3.save()              
    >>> cr4.save() 
    
  • 插入学生表

    >>> from app02.models import Teacher, Student, ClassRoom
    >>> cr1 = ClassRoom.objects.get(pk=1)
    >>> cr1
    <ClassRoom: 初级班>
    >>> cr2 = ClassRoom.objects.get(pk=2) 
    >>> cr2
    <ClassRoom: 中级班>
    >>> cr3 = ClassRoom.objects.get(pk=3) 
    >>> cr3                               
    <ClassRoom: 高级班>
    >>> cr4 = ClassRoom.objects.get(pk=4) 
    >>> cr4
    <ClassRoom: 特级班>
    >>> s1 = Student(name="kobe") 
    >>> s1.save()
    >>> s2 = Student(name='james')
    >>> s2.save()
    >>> s3 = Student(name='wade')  
    >>> s3.save()
    >>> s4 = Student(name='paul')  
    >>> s4.save()
    >>> s5 = Student(name='curry') 
    >>> s5.save()
    >>> s6 = Student(name='tompson') 
    >>> s6.save()                    
    >>> s7 = Student(name='green')   
    >>> s7.save()
    >>> s8 = Student(name='willianms')
    >>> s8.save()
    
  • 建立外键关联

    • 方式一:在多方建立外键关联

      # 给学生添加一个外键属性
      >>> s1.class_room = cr1 # 这里注意,如果没有执行s1.save()数据库不会更新
      >>> s1.save()
      
      
    • 方式二:在一方建立外键关联 add() clear() create() set()

      # 如设置related_name='students' ,给“一方"设置反向字段,一般建议设置这个选项
      >>> cr1.students.add(s1)
      >>> cr1.students.add(s2,s3)  
      # 如没有设置related_name
      >>> cr1.student_set.add(s1)
      >>> cr1.student_set.add(s2)
      # 清楚所有关系
      >>>cr1.students.clear() 
      # 创建一个多方对象,并建立外键关联
      >>> cr2.students.create(name="jordan", age=40)
      >>><Student: <中级班> jordan:40>
      # set() 函数的参数是列表,列表元素是学生对象
      >>> cr3.students.set([s4,s5])
      

4.1.3 多对多数据增加

使用学生和老师模型做多对多关系的测试模型:

学生数据已经添加完成了,就用上面那些。

再创建几条老师的数据:

>>> t1 = Teacher(name='张老师')
>>> t2 = Teacher(name='王老师') 
>>> t3 = Teacher(name='李老师') 
>>> t4 = Teacher(name='赵老师') 
>>> t1.save()  
>>> t2.save()  
>>> t3.save()  
>>> t4.save() 
  • 获取关联模型的结果

    >>> t1.students.all() # 直接获取属性
    <QuerySet []>
    
    >>> s1.teacher_set.all() # 如果ManyToMany没有设置related_name,通过model小写_set获取所有
    <QuerySet []>
    
  • 添加关联数据(没有自定义第三张表的情况)

    # 通过老师关联学生
    >>> t1.students.add(s1,s2,s3) 
    # 关联三条数据app02_teacher_students
    #id  teacher_id  student_id
    #1   1           1
    #2   1           2
    #3   1           3
    >>> t1.students.set([s4, s5])
    # set([]) set函数会清楚之前所有的关系,重写进行设置
    #id  teacher_id  student_id
    #1   1           4
    #2   1           5
    >>> t1.students.clear() 
    # 清除所有的关系,效果等价于t1.students.set([])
    
    # 通过学生关联老师
    >>> s1.teacher_set.add(t1,t2)
    #id  teacher_id  student_id
    #1   1           1
    #2   2           1
    >>> s1.teacher_set.set([t2,t3,t4])
    #id  teacher_id  student_id
    #1   2           1
    #2   3           1
    #3   4           1
    >>>s1.teacher_set.clear()
    # 清除所有的关联关系
    >>> t1.students.add(s1,s2,s3,s4)
    >>> t1.students.remove(s1) # 删除一个已经拥有的关联关系,如果没有这个联系也不会报错 
    
  • 如果通过自定义第三张表做关联(自定义第三张的情况)

    如果有自定义的第三张数据表,并且第三张数据表中有其他字段

    >>>t1.students.add(s1, through_defaults={'other_field':'field_value'})
    

4.2 删除数据

>>> s1.delete() 
(1, {'app02.Student': 1})
#delete() 方法返回一个元组,元组第一个值为已删除的对象个数(即删除的数据行数),元组的第二个值是一个字典,它包含了对象类型和删除的对象个数。

4.3 改变数据

  • 方式一:

    >>> student = Student.objects.get(pk=2) 
    >>> student
    <Student: <初级班> james:34>
    >>> student.age = 100
    >>> student.save()
    
    
  • 方式二:

    >>> Student.objects.filter(id=2).update(age=23)
    1 # 返回更新的记录条数
    >>> Student.objects.filter(id__gte=2).update(age=34)
    7
    

5 查

特别注意:获取objects属性必须使用模型类,不能使用模型实例

>>> s1.objects
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "E:\coding\django_deme_project\.venv\lib\site-packages\django\db\models\manager.py", line 186, in __get__
    raise AttributeError(
AttributeError: Manager isn't accessible via Student instances

**QuerySet **是一个非常关键的对象,后面我们单独章节说这个对象。

5.1 获取全部记录

方法 all() 返回了一个包含数据库中所有对象的 QuerySet 对象。

>>> Student.objects.all() 
<QuerySet [<Student: <初级班> james:100>, <Student: <初级班> wade:34>, <Student: <高级班> paul:34>, <Student: <高级班> curry:34>, <Student: <不明班级> tompson:34>, <Student: <不明班级> green:34>, <Student: <中级班> jordan:34>]>

5.2 过滤器检索对象

5.2.1 filter(**kwargs)

返回一个新的 QuerySet,包含的对象满足给定查询参数。

5.2.2 exclude(**kwargs)

返回一个新的 QuerySet,包含的对象不满足给定查询参数。

5.2.3 详解filter、exclude、get中的关键字参数

field__lookupType=value:注意这里是双下划线,lookupType如果没有,会报错TypeError
Student.objects.filter(name__test=‘james’)
django.core.exceptions.FieldError: Unsupported lookup ‘test’ for CharField or join on the field not permitted.

(1) exact(完全匹配)

如果提供的比较值是 None,它将被解释为 SQL NULL

ORM语法

Student.objects.get(id__exact=2) 
Student.objects.filter(class_room__exact=None)

SQL语法

select * from table where id = 2  
select * from app02_student where class_room_id is null;

(2) iexact(不区分大小写匹配)

如果提供的比较值是 None,它将被解释为 SQL NULL

ORM语法

Student.objects.filter(name__iexact='JaMes') 

SQL语法

select * from app02_student where app02_student.`name` LIKE 'James'

注意事项

不能给外键字段添加iexact选项

Student.objects.filter(classroom__iexact=None) 
# 报错如下:
# django.core.exceptions.FieldError: Related Field got invalid lookup: iexact

(3) contains(区分大小写的包含)

ORM语法

>>> Student.objects.filter(name__contains='p')  
<QuerySet [<Student: <高级班> paul:34>, <Student: <不明班级> tompson:34>]>
>>> Student.objects.filter(name__contains='P') 
<QuerySet []>

SQL语法

select * from app02_student where `name` LIKE '%p%'

(4) icontains(不区分大小写的包含)

ORM语法

>>> Student.objects.filter(name__icontains='P')
<QuerySet [<Student: <高级班> paul:34>, <Student: <不明班级> tompson:34>]>
>>> Student.objects.filter(name__icontains='p') 
<QuerySet [<Student: <高级班> paul:34>, <Student: <不明班级> tompson:34>]>

SQL语法

select * from app02_student where `name` LIKE '%p%'  # LIKE和ILIKE

(5) in(判断字段值是否在一个可迭代对象中)

可迭代对象一般包含元组、列表、字符串

ORM语法

>>> Student.objects.filter(id__in=[1,2,3,4,5])  
<QuerySet [<Student: <初级班> james:100>, <Student: <初级班> wade:34>, <Student: <高级班> paul:34>, <Student: <高级班> curry:34>]>
>>> Student.objects.filter(name__in=['james'])         
<QuerySet [<Student: <初级班> james:100>]>

SQL语法

select * from app02_student where id in (1,2,3,4)
select * from app02_student where name in ('james')

(6) gt(大于)

ORM语法

>>> Student.objects.filter(id__gt=4)          
<QuerySet [<Student: <高级班> curry:34>, <Student: <不明班级> tompson:34>, <Student: <不明班级> green:34>, <Student: <中级班> jordan:34>]>
>>> Student.objects.filter(birthday__gt="1982-9-1")  
<QuerySet [<Student: <高级班> paul:34>]>

SQL语法

select * from app02_student where id > 4 

select * from app02_student where birthday > "1982-9-1"

(7) gte(大于等于)

(8) lt(小于)

(9) lte(小于等于)

(10) startswith(区分大小写的开头)

>>> Student.objects.filter(name__startswith='j')
<QuerySet [<Student: <初级班> james:100>, <Student: <中级班> jordan:34>]>
>>> Student.objects.filter(name__istartswith='J') 
<QuerySet [<Student: <初级班> james:100>, <Student: <中级班> jordan:34>]>
>>> Student.objects.filter(name__startswith='J')  
<QuerySet []>
>>> Student.objects.filter(name__endswith='s')   
<QuerySet [<Student: <初级班> james:100>]>
>>> Student.objects.filter(name__endswith='S') 
<QuerySet []>
>>> Student.objects.filter(name__iendswith='S')
<QuerySet [<Student: <初级班> james:100>]>

SQL语法

# startswith -> j
select * from app02_student where app02_student.`name` LIKE 'j%'

# endswith -> s
select * from app02_student where app02_student.`name` LIKE '%s'

(11)istartswith(不区分大小写的开头)


SQL语法


(12)endswith(区分大小写的结尾)


SQL语法


(13)iendswith(不区分大小写的结尾)


SQL语法


(14)range(范围测试,包含开始和结尾)

>>> start_date = datetime.date(1990,1,1) 
>>> end_date = datetime.date(2022,1,1)  
>>> Student.objects.filter(birthday__range=(start_date, end_date))
<QuerySet [<Student: <中级班> jordan:34>]>

>>> start_date = datetime.date(1980,12,1)                          
>>> end_date = datetime.date(1981,11,1)                            
>>> Student.objects.filter(birthday__range=(start_date, end_date))
<QuerySet [<Student: <初级班> james:100>, <Student: <初级班> wade:34>]>

在这里插入图片描述

SQL语法

select * from app02_student where birthday between "1990-1-1" and "2022-1-1"

(15) 以下是时间相关的查询字段:

(16) date (从日期时间字段取出日期值)

ORM语法

>>> Student.objects.filter(birthday__date__gt='2022-01-01')
<QuerySet [<Student: <高级班> curry:34>, <Student: <不明班级> tompson:34>, <Student: <不明班级> green:34>]>

注意:当 USE_TZ 为 True 时,字段在过滤前会被转换为当前时区

SQL语法


(17) year(从日期时间字段取出年份)

ORM语法

>>> Student.objects.filter(birthday__year__gt='2022')
<QuerySet [<Student: <高级班> curry:34>, <Student: <不明班级> tompson:34>]>
>>> Student.objects.filter(birthday__year='2022')     
<QuerySet [<Student: <不明班级> green:34>]>


SQL语法

select * from app02_student where birthday > '2022-01-01'

select * from app02_student where birthday between '2022-01-01' and '2022-12-31'

(18) iso_year(精确的 ISO 8601 周号年份匹配)

ORM语法

>>> Student.objects.filter(birthday__iso_year__gt='2022')
<QuerySet [<Student: <高级班> curry:34>, <Student: <不明班级> tompson:34>]>
>>> Student.objects.filter(birthday__iso_year='2022')     
<QuerySet [<Student: <不明班级> green:34>]>


SQL语法

(19) month(精确的月份匹配1到12)

ORM语法

>>> Student.objects.filter(birthday__month=12)   
<QuerySet [<Student: <初级班> james:100>, <Student: <中级班> jordan:34>]>

SQL语法

select * from app02_student where EXTRACT(month from birthday) = 12

(20) day(精确的日期匹配1到31)

ORM语法

>>> Student.objects.filter(birthday__day=1)    
<QuerySet [<Student: <初级班> james:100>, <Student: <初级班> wade:34>, <Student: <高级班> paul:34>, <Student: <中级班> jordan:34>]>


SQL语法

select * from app02_student where EXTRACT(day from birthday) = 1

获取所有生日是1号的记录

在这里插入图片描述

(21) week

对于日期和日期时间字段,根据 ISO-8601 ,返回星期号(1-52 或 53),即星期从星期一开始,第一周包含一年的第一个星期四。

ORM语法



SQL语法


(22) week_day

对于日期和日期时间字段,“星期几”匹配。
从 1(星期日)到 7(星期六)取一个整数值,代表一周的一天。

ORM语法



SQL语法


(23) iso_week_day

对于日期和日期时间字段,精确匹配 ISO 8601 星期几。允许链接其他字段的查询。
取一个整数值,代表一周的 1(星期一)到 7(星期日)。

ORM语法



SQL语法


(24) quarter(季度)

ORM语法



SQL语法


(25) time(取datetime中的时间部分)

ORM语法



SQL语法


(26) hour(取datetime中的小时部分)

0~23 的整数

ORM语法



SQL语法


(27) minute(取datetime中的分钟部分)

0~59 的整数

ORM语法



SQL语法


(28) second(取datetime中的秒部分)

0~59 的整数

ORM语法



SQL语法


(29)isnull(取datetime中的秒部分)

取 True 或 False,分别对应 IS NULL 和 IS NOT NULL 的 SQL 查询。

ORM语法



SQL语法


(30)regex(区分大小写的正则表达式匹配)

满足re模块正则的语法

ORM语法



SQL语法

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

(31)iregex(不区分大小写的正则表达式匹配)

满足re模块正则的语法

ORM语法



SQL语法

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

5.3 跨表查询

注意:print(query_set.query) 打印原生SQL查询

5.3.1 多对一跨表查询

教室和学生是一组多对一关系。

  • 查询教室为初级班的所有学生

ORM

>>> s = Student.objects.filter(class_room__name=1)
>>> s
<QuerySet [<Student: <初级班> james:100>, <Student: <初级班> wade:34>]>

SQL

>>> print(s.query)
SELECT 
`app02_student`.`id`, 
`app02_student`.`name`, 
`app02_student`.`age`, 
`app02_student`.`class_room_id`, 
`app02_student`.`birthday` 
FROM `app02_student` INNER JOIN `app02_classroom` 
ON (`app02_student`.`class_room_id` = `app02_c
lassroom`.`id`) 
WHERE `app02_classroom`.`name` = 1
  • 查询学生姓名中有字母j的所有班级

ORM

>>> ClassRoom.objects.filter(students__name__contains='j')
<QuerySet [<ClassRoom: 初级班>, <ClassRoom: 中级班>]>

SQL

>>> cr = ClassRoom.objects.filter(students__name__contains='j')
>>> print(cr.query)
SELECT 
`app02_classroom`.`id`, 
`app02_classroom`.`name` 
FROM `app02_classroom` 
INNER JOIN `app02_student` 
ON (`app02_classroom`.`id` = `app02_student`.`class_room_id`) 
WHERE `app02_student`.`name` LIKE BINARY %j%

5.3.3 多对多跨表查询

学生和老师是一组多对多关系

  • 查询李老师教的所有的学生

ORM

>>> qs=Student.objects.filter(teacher__id=1)           
>>> qs
<QuerySet [<Student: <初级班> james:100>, <Student: <初级班> wade:34>, <Student: <高级班> paul:34>]>

sql

>>> print(qs.query)
SELECT 
`app02_student`.`id`, 
`app02_student`.`name`, 
`app02_student`.`age`, 
`app02_student`.`class_room_id`, 
`app02_student`.`birthday` 
FROM `app02_student` INNER JOIN `app02_teacher_students` 
ON (`app02_student`.`id` = `app02_teacher_students`.`student_id`) 
WHERE `app02_teacher_students`.`teacher_id` = 1

  • 查询james、curry、green这些同学的老师

ORM

>>> qs = Teacher.objects.filter(students__name__in=['james','green', 'curry'])
>>> qs
<QuerySet [<Teacher: <Teacher> 张老师>]>

SQL

>>> print(qs.query)
SELECT 
`app02_teacher`.`id`, 
`app02_teacher`.`name` 
FROM `app02_teacher` INNER JOIN `app02_teacher_students` 
ON (`app02_teacher`.`id` = `app02_teacher_students`.`teacher_id`) 
INNER JOIN `app02_student` 
ON (`app02_teacher_students`.`student_id` = `app02_student`.`id`) 
WHERE `app02_student`.`name` IN (james, green, curry)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/135058.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot+Vue前后端分离的招聘管理系统(程序+数据库+文档)

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

A Survey on Deep Learning Techniques for Stereo-based Depth Estimation论文阅读

1. 摘要 估计RGB图片的深度是一个长期存在的病态问题&#xff0c;计算机视觉、图形学、机器学习社区已经探索了数十年。立体匹配是最广泛见诸文献的技术之一&#xff0c;因为它与人类的双目系统有强关联。传统上&#xff0c;利用多张图片的人工特征匹配来处理基于立体的深度估…

nginx 实现图片防盗链功能

在搜索浏览网页的时候&#xff0c;发现一篇文章是从我的个人网站转载的&#xff0c;但是没有注明出处&#xff0c;文章中的图片也没有本地化处理&#xff0c;还是从我的服务器请求&#xff0c;这就无形中增加了我的服务器的开销&#xff0c;于是有了设置防盗链功能这一想法。 …

Kafka 核心源码解读【五】--延迟操作模块

文章目录1 TimingWheel&#xff1a;探究Kafka定时器背后的高效时间轮算法1.1 时间轮简介1.2 源码层级关系1.3 时间轮各个类源码定义1.3.1 TimerTask 类1.3.2 TimerTaskEntry 类1.3.3 TimerTaskList 类1.3.4 TimingWheel 类1.4 总结2 DelayedOperation&#xff1a;Broker是怎么延…

【Vue】九、vue-element-admin

后端程序员的vue学习之路一、介绍二、功能特性三、前置准备四、前置知识五、项目结构说明&#xff1a;六、安装运行一、介绍 vue-element-admin 是一个后台前端解决方案&#xff0c;它基于 vue 和 element-ui实现&#xff0c;它使用了最新的前端技术栈&#xff0c;内置了动态路…

深入理解计算机系统_程序的链接过程

编辑好的程序&#xff0c;依次经过预处理(注释&#xff0c;宏替换&#xff0c;头文件包含&#xff0c;生成.s文件)、编译(生成汇编文件.s )、汇编(生成静态可重定位目标文件&#xff0c;文件名是.o)、链接后最终得到可执行目标文件&#xff0c;这个笔记记录一下&#xff0c;链接…

信号处理系列之死区滤波器(DeadZone)

信号处理专栏相关限幅滤波的文章,可以参看下面的链接,这里不再赘述: 博途PLC信号处理系列之限幅消抖滤波_RXXW_Dor的博客-CSDN博客关于限幅滤波可以参看下面这篇文章PLC信号处理之限幅滤波(西门子三菱FB)_RXXW_Dor的博客-CSDN博客限幅滤波是一种消除随机干扰的有效方法,比…

WordPress元宇宙和VR(虚拟现实)最佳插件汇总

近年来&#xff0c;虚拟现实&#xff08;VR &#xff09;和元宇宙&#xff08;Metaverse &#xff09;变得越来越流行。它使用户能够在舒适的家中享受身临其境的体验。此外&#xff0c;将此功能添加到您的网站可以帮助您的内容更具交互性&#xff0c;这可能会带来更多转化。幸运…

RHCE——ansible安装配置(2)

安装并且配置ansible&#xff1a; 1)安装和配置ansible以及ansible控制节点server.example.com如下&#xff1a; 2)创建一个名为/home/student/ansible/inventory的静态库存文件如下所示&#xff1a; 2.1)node1 是dev主机组的成员 2.2)node2是test主机组的成员 2.3)node1和node…

c++动态内存管理

1.回顾c语言中的动态内存管理 在c语言中&#xff0c;我们想要动态开辟一段空间&#xff0c;需要使用malloc&#xff0c;calloc&#xff0c;realloc几个函数 void* malloc (size_t size); //在堆上申请size个字节的空间void* calloc (size_t num, size_t size); //第一个参数是…

压缩空气储能研究(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

CMMI之技术预研

技术预研&#xff08;Technical Pre-Research, TPR&#xff09;是指在立项之后到开发工作完成之前的时间内&#xff0c;对项目将采用的关键技术提前学习和研究&#xff0c;以便尽可能早地发现并解决开发过程中将会遇到的技术障碍。 技术预研过程域是SPP模型的重要组成部分。本…

Android实现轮播控件Banner

背景 最近做需求要实现一个轮播图&#xff0c;最后通过HandlerViewPager实现了需求&#xff0c;所以把实现的过程总结一下&#xff0c;方便以后学习参考&#xff0c;以下是轮播图的效果&#xff1a; 实现思路 定时轮播 利用HandlerViewPager&#xff0c;Handler发送定时消息切…

初探Scala

目录 Scala介绍 Scala 环境搭建 IDEA新建Maven工程 创建执行输出Hello Scala Scala中main方法语法的详细解读 class 和 object 说明 Scala介绍 一般来说&#xff0c;学 Scala 的人&#xff0c;都会 Java&#xff0c;而 Scala 是基于 Java 的&#xff0c;因此我们需要将 S…

CSS基础总结(五)定位

文章目录 1.为什么需要定位 2.定位的组成 2.1公式 2.2定位模式 2.2.1静态定位static 2.2.2相对定位relative 2.2.3绝对定位absolute 2.2.4固定定位fixed 2.2.5粘性定位sticky 总结 2.3边偏移 3.定位叠放次序 4.定位拓展 4.1子绝父相布局法 4.2固定于版心右侧位置方…

read and write

read and write The read and write methods both perform a similar task, that is, copying data from and to application code. Therefore, their prototypes are pretty similar, and its worth introducing them at the same time: read 和 write 方法都执行类似的任务&…

Java开发 - 常用算法深度讲解,让你再也不会忘记

目录 前言 冒泡排序 原理 选择排序 原理 插入排序 原理 二分查找排序 原理 结语 前言 经常会有一些算法&#xff0c;我们说常用不常用&#xff0c;说不用也偶尔会用&#xff0c;当时看记住了&#xff0c;过几天提起来又忘记了&#xff0c;这是为什么呢&#xff1f;以…

Spring Security:PasswordEncoder密码加密匹配操作

目录 PasswordEncoder SpringBoot&#xff1a;注入BSryptPasswordEncoder实例 BSryptPasswordEncoder详解 父接口PasswordEncoder BSryptPasswordEncoder及其使用 成员方法 SecurityUtils安全服务工具类 测试代码 PasswordEncoder PasswordEncoder是Spring Security框架…

51单片机学习笔记_4 IO扩展:LED 点阵

IO 扩展(串转并)-74HC595 前面接的一些输入输出设备都是直接连接的单片机 IO 口&#xff0c;单片机仅有的 IO 口非常有限。而使用 IO 扩展可以大量增加可使用的端口。比如后面要使用的 LED 点阵&#xff0c;8*8个格子&#xff0c;使用扩展 IO 输入就更为合适。如果多级联一个&…

20230102单独编译原厂RK3588开发板的开发板rk3588-evb1-lp4-v10的Android12的内核2

20230102单独编译原厂RK3588开发板的开发板rk3588-evb1-lp4-v10的Android12的内核2 2023/1/2 21:01 《RK3588_Android12_SDK_Developer_Guide_CN.pdf》 原厂的开发板rk3588-evb1-lp4-v10单独编译内核的方式&#xff1a; cd kernel-5.10 export PATH../prebuilts/clang/host/lin…