一、ORM常用字段与不常用字段

AutoField

int类型且自增,必须填入参数 primary_key=True。当model中如果没有自增字段,则自动会创建一个名为id的字段,并设置为主键、自增。


IntegerField

整数类型,其数值范围在 -2147483648 - 2147483647。


CharField

字符类型,必须提供max_length参数, max_length表示字符长度。


DateField

日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。格式为:年-月-日

常用参数:

  •   auto_now_add = True:创建数据记录的时候会把当前时间添加到数据库, 更改记录不会发生变动。
  • auto_now = True:每次更新数据记录的时候会更新该字段。

DateTimeField

日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。格式为:年-月-日 时:分:秒:毫秒

常用参数如DateField一致

FloatField

浮点数类型,小数越长越不精准


DecimalField

使用 Decimal 实例表示固定精度的十进制数的字段。它有两个必须的参数:

  • max_digits:数字允许的最大位数
  • decimal_places:小数的最大位数

 TextField(Field)- 大段文本类型

不常用字段:

BigAutoField(AutoField)
- bigint类型且自增列,必须填入参数 primary_key=True

SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647

BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

BooleanField(Field)
- 布尔值类型

NullBooleanField(Field):
- 可以为空的布尔值

TextField(Field)
- 文本类型

EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制

IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"

URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL

SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字

UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path,                      文件夹路径
match=None,                正则匹配
recursive=False,           递归下面的文件夹
allow_files=True,          允许文件
allow_folders=False,       允许文件夹

FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = ""      上传文件的保存路径
storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = ""      上传文件的保存路径
storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None,   上传图片的高度保存的数据库字段名(字符串)
height_field=None   上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field)
- 日期格式      YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field)
- 时间格式      HH:MM[:ss[.uuuuuu]]

DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

BinaryField(Field)
- 二进制类型


二、常用参数

2.1 任意字段都可以设置的参数
null

用于表示某个字段可以为空。设置方式:null = True

unique

用于表示该字段值在此表中必须是唯一的,建立唯一索引,设置方式:unique = True

db_index

将该字段设置为索引,设置方式:db_index = True

default

为该字段的默认值,设置方式:default = ‘默认值’

db_column

在数据库中的字段名称,默认和变量同名,设置方式:db_column=‘字段名’

primary_key

设置字段为主键,设置方式:primary_key = True。通常id字段为主键,且唯一主键

2.2 日期字段参数
unique_for_date: 日期必须唯一

unique_for_month: 月份必须唯一

unique_for_year: 年份必须唯一

auto_now_add: 增加记录时的时间

auto_now: 更新当前记录的时间

2.3 用于Admin后台管理参数

verbose_name:Admin中显示的字段名称
blank:Admin中是否允许用户输入为空
editable :Admin中是否可以编辑
help_text:Admin中该字段的提示信息
choices:Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作(设置方式:choice=((1,‘男’),(2,‘女’),(0,‘未知’)) )

三、关系字段

表之间的关系由一对一、一对多、多对多来确定的,在之前章节有提到过。

3.1 ForeignKey外键
通过外键来绑定各个表字段之间的关系

to:关联哪张表、设置方式to = ‘关联表名’

to_field:关联表的哪个字段(默认关联主键)

related_name:反向查询时使用的字段名,用于代替原来反向查询的表名_set

related_query_name:反向查询操作时 使用的连接前缀,用于代替表名。相当于给表设置了一个别名

on_delete参数设置的值

models.CASCADE:删除关联数据,与之关联也删除

models.DO_NOTHING:删除关联数据,什么都不做

models.PROTECT:删除关联数据,引发错误ProtectedError

models.SET_NULL:删除关联数据,搭配null = True使用,使之关联的值为null

models.SET_DEFAULT:删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)

models.SET:删除关联数据,设置为一个传递给SET()的值或者一个回调函数的返回值,注意大小写

db_constraint:保留跨表查询的方式,但是在table之间不建立外键关联(但是在Django内可以有一个关联状态,可以在admin里面看到),一般都设置为False,减少过多的约束。此时on_delete参数需要设置为models.SET_NULL、blank=True、null=True允许字段为空,这样即使关联的外键数据被删除了,也只会将字段设置为null。

四、OneToOneField与ForeignKey的区别

OneToOneField用于一对一关系的表之间进行关联。

根据Django官方文档介绍:

A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.

OneToOneField与ForeignKey加上unique=True效果基本一样,但是用OneToOneField反向关联会直接返回对象。

相反地,使用ForeignKey, 反向关联后会返回QuerySet。

例如:Book表通过ForenignKey与Publish表建立了外键

obj = models.Publish.objects.filter(pk=1).first()
print(obj.book_set.all()) # 通过ForenignKey进行关联所以反向查询必须要加表名小写_set.all()
执行结果:拿到的是一个QuerySet对象

<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>

Author表通过OneToOneField与AuthorDeatil表建立了外键

obj = models.AuthorDeatil.objects.filter(pk=1).first()
print(obj.author) # 通过OneToOneField进行关联的反向查询不需要_set.all()
执行结果

Author object (1)

五、多对多关系建立的方式

两张表之间多对多的关系通常需要借助第三张表来存储,这样也更利于我们查询。而第三张表的建立有三种方式:

第一种:自动创建(常用:但是创建出来的第三张表没有其它字段,只存有这两张表的主键相互对应关系)
第二种:半手动创建(比较常用:第三张表我们可以建立其它字段,但也不影响两张表的关联)
第三种:完全手动建立第三张表。
第一种方式:通过ORM自带的ManyToManyField自动创建第三张表

class Book(models.Model):
     title = models.CharField(max_length=32, verbose_name="书名")
     
 class Author(models.Model):
     name = models.CharField(max_length=32, verbose_name="作者姓名")
     books = models.ManyToManyField(to="Book", related_name="authors")


    # 每次可以将Author表与Book表对应关系的主键值存储到第三张表

这种建立第三张表具备多个:多对多关系操作API

author_obj.books.add():括号内填写与作者关联的书籍对象 或者 书籍的主键值
author_obj.books.set():清空该作者原来关联的书籍,传入一个可迭代对象(里面可以包含一个或多个书籍对象 或者 书籍主键值)
author_obj.books.clear():清空该作者关联的书籍
author_obj.books.remove():移除该作者关联的某个书籍

第二种方式:自己创建第三张表,并通过ManyToManyField指定关联

class Book(models.Model):
     title = models.CharField(max_length=32, verbose_name="书名")class Author(models.Model):
     name = models.CharField(max_length=32, verbose_name="作者姓名")
     books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
     # through_fields 元组的第一个值是ManyToManyField所在的表去中间表通过那个字段,就写在第一个位置。我们要通过author字段去中间表,因为author class Author2Book(models.Model):
     author = models.ForeignKey(to="Author")
     book = models.ForeignKey(to="Book")


through:指定我们手动创建的中间表

through_fields:指定关联字段,设置方式通过元组,值也就是关联第三张表的哪几个字段,注意先后顺序:如果book写在前面则表示我们从Author表到中间表要通过book字段,那么就会乱套了

第三种方式:自己创建第三张表,分别通过外键关联书和作者

class Book1(models.Model):
     title = models.CharField(max_length=32, verbose_name="书名")
     
 class Author1(models.Model):
     name = models.CharField(max_length=32, verbose_name="作者姓名")class Author2Book1(models.Model):
     author = models.ForeignKey(to="Author")
     book = models.ForeignKey(to="Book")



这种方式创建的多对多关系很多API操作都用不了,需要手动指定,如果要跨表查询将不能通过obj.表名小写或者obj.表名小写_set.all(),而是每次都要通过中间表来实现。

六、Meta元信息

Meta是Django模型类里面的一个内部类,它用于定义一些Django模型类的行为特性。

定义方式:

class Author(models.Model):
     class Meta:
         pass



通常在里面定义变量来代表选项,而可用的选项大致包含以下几类:

1、db_table

自定义表名(通常表名都是由Django帮助我们创建的,且是由:项目_类名组合的)

2、index_together

为多个字段建立联合索引,设置方式:index_together = ('name','age')

3、unique_together

当需要通过两个字段保持模型唯一性时使用,假设有一个 User 类,我们希望 User 的 username 和 email 两个属性的组合必须是唯一的,那么需要设置为:

unique_together = (("username", "email"),)

当某个一行记录:username='jack'、email='123@qq.com,那么其它行就不能同时这两个字段值都设置的和那一行一样。

unique_together 的值是一个元组的元组。为了方便起见,处理单一字段的集合时unique_together 可以是一维的元组

unique_together = ("driver", "restaurant")

这样就确保了driver与restaurant字段值是唯一的

4、ordering

根据哪个字段排序,设置方式:ordering = ('id',)

可配置参数
属性    描述

db_table = 'xxx'    修改表名为xxx
 ordering = 'xxx'    按照指定字段xxx排序
 verbose_name = 'xxx'    给模型类指定一个直观可读的信息xxx
 verbose_name_plural = verbose_name    设置verbose_name的复数
 abstract = True    设置模型类为一个基类(不会生成为表,只作为继承使用)
 permissions = (('定义好的权限', '权限说明'),)    给数据库的表设置额外的权限
 managed = False    是否按照django既定的规则来管理模型类
 unique_together = ('address', 'note')    联合唯一键,约束
 app_label = 'xxx'    定义模型类属于哪一个应用
 db_tablespace    定义数据库表空间的名字

七、ORM中执行SQL语句
在Django的ORM中我们也是可以使用原生SQL来进行操作的,其实我们并不能完全依赖于ORM框架来提供给我们操作数据库的便利,因为ORM在很多语言中使用形式都会有些不同,而SQL语句则是不变的。

实例:我们不需要管是基于什么对象来执行SQL语句,查出什么字段就可以直接使用

res = models.Author.objects.raw('select * from app01_book where id > 1')
 for book in res:
     print(book.name,book.price,book.publish_time)



执行结果

西游记 75.5 2021-03-24
三国演义 80.0 2021-03-24
总结:执行原生sql,跟对象类型无关了,查出什么字段,可以直接使用该字段。

ps:但是基于的不同对象执行SQL语句,得到的结果也会是不同的,有些字段数据还是用不了