20 Jun 18
今日内容(Django之ORM)
https://www.cnblogs.com/liwenzhou/p/8688919.html
一、 一些说明
1. 如果自定义表名,需要在model的Meta类中指定db_table 参数,强烈建议使用小写表名,特别是使用MySQL作为后端数据库时。
# 如果自定义表名不使用小写,后续可能出bug
2. id字段可自动添加的,如果想指定自定义主键,只需在其中一个字段中指定primary_key=True 即可。如果Django发现已经明确地设置了Field.primary_key,它将不会添加自动ID列。
3. Django会根据配置文件中指定的数据库后端类型来生成相应的SQL语句。
4. Django支持MySQL5.5及更高版本。
二、ORM常用字段
1. AutoField:int自增列,必须填入参数primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
2. CharField: varchar字符类型,必须有max_length参数(表示字符长度)。
# 手机号一般使用CharField字段
# 如果想使用char,自定义使用(详见后续)
3. ForeignKey
4. ManyToManyField
5. IntegerField: 一个整数类型,范围在-2147483648 to 2147483647。
6. DateField: 日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
7. DateTimeField: 日期时间字段,格式YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
8. EmailField(CharField):varchar + 校验
9. FloatField(Field): 浮点数不是很精确,如果想稍精确些,可考虑先乘以100->运算->再除以100
10. DurationField(Field): 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
# 可用于优惠券有效期等方面
import datetime
now = datetime.datetime.now()
print(now) # 2018-06-20 14:38:41.855698
d7 = datetime.timedelta(days=7)
y1 = datetime.timedelta(weeks=52)
print(now + d7) # 2018-06-27 14:38:41.855698
print(now + y1) # 2019-06-19 14:38:41.855698
11. DecimalField: 10进制小数; 要有参数max_digits(小数总长度),和参数decimal_places(小数位长度)
12. ImageField(FileField):后续项目会用到(用户上传的头像)
13. CommaSeparatedIntegerField(CharField):字符串类型,格式为逗号分割的数字
14.自定义字段
a. 自定义char类型字段
class FixedCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
cname = FixedCharField(max_length=25)
b.其他
class UnsignedIntegerField(models.IntegerField):
def db_type(self, connection):
return 'integer UNSIGNED'
15. 附ORM字段与数据库实际字段的对应关系(如需要,回来查找)
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
三、orm中的常用字段参数
1. null: 用于表示某个字段可以为空。
2. unique: 如果设置为unique=True 则该字段在此表中必须是唯一的 。
3. db_index: 如果db_index=True 则代表着为此字段设置索引。(用来加速查找)
4. default:为该字段设置默认值。
5. 对于DateField和DateTimeField字段,可使用以下两个参数
a. auto_now_add:配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
b. auto_now:配置上auto_now=True,每次更新数据记录的时候会更新该字段。
# 注意,两者不能同时使用
四. ORM标语表之间的关系(关系字段)
1. 外键关联ForeignKey:一般把ForeignKey字段设置在'一对多'中'多'的一方
a. to: 设置要关联的表
设置要关联的表时,可以将被关联的表放在前面,关联表放在后面;或在被给to所传的值加''(如to='book'),以防止报错
b. to_field: 设置要关联的表的字段
c. on_delete: 当删除关联表中的数据时,当前表与其关联的行的行为。
1)models.CASCADE: 删除关联数据,与之关联也删除
2)models.DO_NOTHING:删除关联数据,引发错误IntegrityError
3)models.PROTECT:删除关联数据,引发错误ProtectedError
4)models.SET_NULL:删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
5)models.SET_DEFAULT:删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
6)models.SET:删除关联数据,
i)与之关联的值设置为指定值,设置:models.SET(值)
ii)与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
# Django1.1默认on_delete = models.CASCADE; Django2没有上述默认,需要时手动添加
d. db_constraint: 是否在数据库中创建外键约束,默认为True
# 当设置db_constraint=False,相当于解除了外键的绑定效果,即再无外键关联。
# 项目中,推荐使用。一来通过程序后台逻辑操控,而不是数据库层面的硬性绑定,保证数据质量。这种方式更灵活,且值得推崇。二来,提示有外键关系存在,使程序可读性更强。
class Book(models.Model):
title = ZhangZhaoCharField(max_length=16) # char(16)
publisher_date = models.DateField(auto_now_add=True)
price = models.DecimalField(max_digits=5, decimal_places=2, default=9.9)
publisher = models.ForeignKey(to=Publisher, on_delete=models.CASCADE, db_constraint=False)
def __str__(self):
return "{}:{}".format(self.title, self.price)
2. 一对一(OneToOneField): 通常一对一字段用来扩展已有字段。
字段参数:to to_field on_delete
# 比如第三方登陆时,开放一些信息给第三方平台时可能用到
# 不是所有的信息都被需要,一来保证了信息的相对安全,二来加快了信息查找的速度。
class User(models.Model):
name = models.CharField(max_length=16)
gender_choice = ((1, "男"), (2, "女"), (3, "保密"))
gender = models.SmallIntegerField(choices=gender_choice, default=3)
detail = models.OneToOneField(to='UserInfo')
class UserInfo(models.Model):
phone = ZhangZhaoCharField(max_length=11, unique=True, db_index=True)
addr = models.TextField()
hunfou = models.BooleanField()
3. 多对多(ManyToManyField): 用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系。
a. 多对多关系的第一种方式:使用ManyToManyField() --> ORM自动帮我创建第三张表
class Author(models.Model):
name = models.CharField(max_length=32)
books = models.ManyToManyField(to="Book", db_table="author2book")
class Meta:
db_table = "author" # db_table:默认创建第三张表时,数据库中表的名称。
优点: 快捷,且可以直接通过authoe_obj.books.all()调出所有相关对象
缺点:如果想在第三张表上添加额外的数据,不是很方便
b. 多对多关系的第二种方式:手动创建第三张表
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
id = models.AutoField(primary_key=True)
book = models.ForeignKey(to=Book)
author = models.ForeignKey(to=Author)
first_blood = models.DateField()
优点:如果想在第三张表上添加额外的数据,相对很方便
缺点: 但从Book表或Author表中,看不出彼此的关联关系
c. 第三种创建多对多的方式:手动创建第三张表并设置ManyToManyField(),指定books = models.ManyToManyField。。。。
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
books = models.ManyToManyField(
to="Book", # to:设置要关联的表
through="Book2Author", # through:指定第三张表的表名。
through_fields=('author', 'book')# through_fields:设置关联的字段。
)
# 在使用through_fields时,括号中的参数为第三张表中的参数;且放在第一位的必须是当前表中可以通过其联系第三张表的那个参数
class Book2Author(models.Model):
id = models.AutoField(primary_key=True)
book = models.ForeignKey(to=Book)
author = models.ForeignKey(to=Author)
first_blood = models.DateField()
优点:如果想在第三张表上添加额外的数据,相对很方便。 且可以看出不同表间的关联关系
缺点: 可以查,但有些设置(如set)不可以使用
五、补充:使用Django时,获取Django的环境配置,以完成小测试的三种方式
1. 在python console中
2. 在terminal中输入python3 manage.py shell
3. 在py脚本中,加载Django的项目配置信息;类似manage.py前面的配置
import os
if __name__ == '__main__':
# 指定当前py脚本需要加载的Django项目配置信息
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_demo.settings")
# 启动Django项目
import django
django.setup()
from app01 import models
六. ORM查询操作必知必会13条
https://www.cnblogs.com/liwenzhou/p/8660826.html
filter()支持 双下划线 操作!
总结一下:
1. 返回QuerySet类型的都有哪一些
1. all(): 查询所有结果
ret = models.Book.objects.all() # QuerySet类型 --> 书籍对象的列表
2. filter(): 它包含了与所给筛选条件相匹配的对象
# filter和get类似。但filter返回的是对象的列表,get返回的是对象;且如果没有,filter返回empty set,而get直接报错
# 综上,一般项目中用filter,而不使用get
ret = models.Book.objects.filter(title="围城") # QuerySet类型 --> 书籍对象的列表
ret = models.Book.objects.filter(id=1) # QuerySet类型 --> 书籍对象的列表
ret = models.Book.objects.filter(id__gt=1) # QuerySet类型 --> 书籍对象的列表
ret = models.Book.objects.filter(id__lt=3) # QuerySet类型 --> 书籍对象的列表
ret = models.Book.objects.filter(publisher_date__year=2017) # QuerySet类型 --> 书籍对象的列表
ret = models.Book.objects.filter(publisher_date__year__gt=2017) # QuerySet类型 --> 书籍对象的列表
# 可以__连__
ret = models.Book.objects.filter(title__contains="曌") # QuerySet类型 --> 书籍对象的列表
ret = models.Book.objects.filter(title__contains="曌", publisher_date__year=2018) # QuerySet类型 --> 书籍对象的列表
# 同时满足条件一和条件二
models.Tb1.objects.filter(name__icontains="ven")# icontains大小写不敏感
models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and
类似的还有:startswith,istartswith, endswith, iendswith
3. exclude():它包含了与所给筛选条件不匹配的对象
ret = models.Book.objects.exclude(id__in=[1,3,4])
4. order_by():对查询结果排序
ret = models.Book.objects.all().order_by("price") # QuerySet类型 --> 根据price字段对所有数据排序
ret = models.Book.objects.all().order_by("-price") # QuerySet类型 --> 根据price字段对所有数据排序
# -price 数字类可以如上操作以得到反序列
ret = models.Book.objects.all().order_by("price").reverse() # QuerySet类型 --> 根据price字段对所有数据排序
ret = models.Book.objects.all().order_by("publisher_date").reverse().values("title") # QuerySet类型 --> 根据price字段对所有数据排序
5. reverse():对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
#先要产生一个QuerySet,然后才能用reverse()排序
6. distinct():从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
# distinct()的()内不能加参数,否则mysql不支持
ret = models.Book.objects.all().values("publisher__name").distinct() # QuerySet类型 --> 根据price字段对所有数据排序
7. values():返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
# values()和values_list()之后不能在追加了
ret = models.Book.objects.filter(publisher_date__year=2018).values("title", "publisher_date") # QuerySet类型 --> 字段及字段值的字典的列表
8. values_list():它与values()非常相似,它返回的是一个可迭代的元组序列,values返回的是一个字典序列
ret = models.Book.objects.filter(publisher_date__year=2018).values_list("title", "publisher_date") # QuerySet类型 --> 字段值的元祖的列表
2. 返回具体对象:
1. get():返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
2. first():返回第一条记录
ret = models.Book.objects.all().first() # 对象 --> 结果集中的第一个数据
3. last():返回最后一条记录
3. 返回具体数字:
1. count():返回数据库中匹配查询(QuerySet)的对象数量。
ret = models.Book.objects.all().count() # 数字 --> 结果集中数据的个数
4. 返回布尔值的:
1. exists():如果QuerySet包含数据,就返回True,否则返回False
ret = models.Book.objects.all().exists() # 布尔值 --> 结果集中是否有数据