模型层
关键字字段及参数:
AutoField:
int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列
IntegerField:
一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存)
CharField:
字符类型,必须提供max_length参数, max_length表示字符长度。(数据库中的varchar类型)。
# 自定义char类型
from django.db import models
# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
'''
自定义的char类型的字段类
'''
def __init__(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)
def db_type(self, connection):
'''
限定生成的数据库表字段类型char,长度为max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
gender_choice=((1,'男'),(2,'女'),(3,'保密'))
gender=models.SmallIntegerField(choices=gender_choice,default=3)
DateField:
日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
DateTimeField:
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
配置上auto_now=True,每次更新数据记录的时候会更新该字段。
字段集合:
AutoField(Field)
- int自增列,必须填入参数 primary_key=TrueBigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import modelsclass UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807BooleanField(Field)
- 布尔值类型NullBooleanField(Field):
- 可以为空的布尔值CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度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中提供验证 URLSlugField(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.FileSystemStorageImageField(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-DDTimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型FloatField(Field)
- 浮点型DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度BinaryField(Field)
- 二进制类型字段合集
ORM字段与MySQL字段对应关系
对应关系:
'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)',
字段参数
null: 用于表示某个字段可以为空。
unique:如果设置为unique=True 则该字段在此表中必须是唯一的 。
db_index:如果db_index=True 则代表着为此字段设置索引。
default:为该字段设置默认值。
单独的py文件测试ORM操作需要配置的参数
主要是queryset对象就可以无限制的点queryset方法。
models.User.objects.filter().filter().filter().count()
import os
if __name__ == "__mian__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
import django
django.setup()
from app01 import models # 这句话必须在下面导入,因为django环境创建才能导入
新增数据
# 基于create创建:
user_obj = models.User.objects.create(name='jason',age=18,register_time='2019-6-12')
print(user_obj.register_time)
# 基于对象的绑定方法创建
user_obj = models.User(name='kiven', age=30, register_time='2019-1-1')
user_obj.save()
修改数据
# 基于对象
user_obj = models.User.objects.filter(name='jason').first()
user_obj = 17
user_obj.save()
# 基于queryset
user_obj = models.User.objects.filter(name='jason').update(age=66)
删除数据
# 基于queryset
models.User.objects.fileter(name='jason').delete()
# 基于对象
user_obj = models.User.objects.filter(name='egon').first()
user_obj.delete()
表单查询
<1> all(): 查询所有结果
<2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象,注意多个条件之间是and关系
<3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
<4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
<5> order_by(*field): 对查询结果排序('-id')/('price') 默认升序
<6> reverse(): 对查询结果反向排序 >>>前面要先有排序才能反向
<7> count(): 返回数据库中匹配查询(QuerySet)的对象数量。
<8> first(): 返回第一条记录
<9> last(): 返回最后一条记录
<10> exists(): 如果QuerySet包含数据,就返回True,否则返回False
<11> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
<12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
<13> distinct(): 从返回结果中剔除重复纪录(完全相同的数据包括id)
表单查询之神奇的双下划线查询
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的
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
date字段还可以:
models.Class.objects.filter(first_day__year=2017)
date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据
# date
#
# Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)
# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)
# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)
# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)
需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~
多表操作
表和表之间的关系:
- 一对一((OneToOneField):一对一字段无论建在哪张关系表里面都可以,但是推荐建在查询频率比较高的那张表里面
- 一对多(ForeignKey):一对多字段建在多的那一方
- 多对多(ManyToManyField):多对多字段无论建在哪张关系表里面都可以,但是推荐建在查询频率比较高的那张表里面
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
publish = models.ForeignKey(to='Publish') # to_filed=关联其他字段名,默认主键名
authors = models.ManyToManyField(to='Author') # 多对多关系 # 虚拟字段 信号字段
class Author(models.Model):
name = models.CharField(max_length=16)
age = models.IntegerField()
authordatail = models.OneToOneField(to='AuthorDatail') # 一对一关系
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
email = models.EmailField()
class AuthorDatail(models.Model):
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
新增:
# 直接写id
models.Book.obects.create(title='十万个为什么',price=99.9,publish_id=1)
# 传数据对象
publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book(title='十万个为什么',price=99.9,publish=publish_obj)
修改:
# 基于queryset修改
models.Book.objects.filter(pk=1).update(publish_id=3)
publish_obj=models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
# 基于对象的修改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.publish_id =3 # 点表中真实存在的字段名
book_obj.save()
book_obj = models.Book.objects.filter(pk=1).first()
publish_obj = models.Publish.objects.filter(pk=2).first()
book_obj.publish = publish_obj # 点orm中字段名,传该字段对应的表的数据对象
book_obj.save()
删除:
# 基于queryset
models.Book.objects.filter(pk=1).delete()
models.Publish.objects.filter(pk=2).delete()
# 基于对象
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.delete()
给书籍绑定与作者之间的关系 add() 多对多
# 给书籍绑定与作者之间的关系(在多对多关系自动生成的表中)
# 添加关系 add: add支持传数字或对象,并且可以传多个
book_obj = models.Book.objects.filter(pk=6).first()
# book_obj.authors.add(1)
# book_obj.authors.add(2, 3)
author_obj = models.Author.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
# book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj, author_obj1) #传入多个值
修改书籍与作者的关系 set()
# 修改书籍与作者的关系 set() set()传的必须是可迭代对象
# book_obj = models.Book.objects.filter(pk=6).first()
# 可以传数字或对象,并且支持多个
# book_obj.authors.set((1,)) #我们以元组的形式传值举例
# book_obj.authors.set((1, 2, 3))
# author_list = models.Author.objects.all()
# book_obj = models.Book.objects.filter(pk=6).first()
# book_obj.authors.set(author_list)
删除书籍与作者的绑定关系 remove()
book_obj = models.Book.objects.filter(pk=9).first()
book_obj.authors.remove(1)
book_obj.authors.remove(2,3)
# author_obj = models.Authors.objects.all().first()
author_list = models.Author.objects.all()
# book_obj.authors.remove(author_obj)
book_obj.authors.remove(*author_list) #需将queryset打散
清空 clear() 清空你当前这个表记录对应的绑定关系
book_obj = models.Book.ojects.filter(pk=9).first()
book_obj.authors.clear()
基于对象的跨表查询
正向查询和反向查询的概念:正向查询按字段,反向查询按表名小写。
一对一:
- 正向:author————关联字段在author表里————authordetil 按字段
- 反向: authordetil————关联字段在author表里————author 按表名小写
一对多:
- 正向:book————关联字段在book表里————publish 按字段
- 反向:pblish————关联字段在book表里————book 按表名小写_set.all() 一个出版社对应多本图书
多对多:
- 正向:book————关联字段在book表里————author 按字段
- 反向:author————关联字段在book表里————book 按表名小写_set.all() 一个作者对应多本图书
# 基于对象的跨表查询
# 正向
# 查询书籍是三国演义的出版社邮箱
# book_obj = models.Book.objects.filter(title='三国演义').first()
# print(book_obj.publish.email)
# 查询书籍是金瓶梅的作者的姓名
# book_obj = models.Book.objects.filter(title='金瓶梅').first()
# print(book_obj.authors) # app01.Author.None
# print(book_obj.authors.all())
# 查询作者为jason电话号码
# user_obj = models.Author.objects.filter(name='jason').first()
# print(user_obj.authordetail.phone)
# 反向
# 查询出版社是东方出版社出版的书籍 一对多字段的反向查询
# publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# print(publish_obj.book_set) # app01.Book.None
# print(publish_obj.book_set.all())
# 查询作者jason写过的所有的书 多对多字段的反向查询
# author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all())
# 查询作者电话号码是110的作者姓名 一对一字段的反向查询
# authordetail_obj = models.AuthorDetail.objects.filter(phone=110).first()
# print(authordetail_obj.author.name)
# 基于双下滑线的查询
# 正向
# 查询书籍为三国演义的出版社地址
# res = models.Book.objects.filter(title='三国演义').values('publish__addr','title')
# print(res)
# 查询书籍为金瓶梅的作者的姓名
# res = models.Book.objects.filter(title='金瓶梅').values("authors__name",'title')
# print(res)
# 查询作者为jason的家乡
# res = models.Author.objects.filter(name='jason').values('authordetail__addr')
# print(res)
# 反向
# 查询南方出版社出版的书名
# res = models.Publish.objects.filter(name='南方出版社').values('book__title')
# print(res)
# 查询电话号码为120的作者姓名
# res = models.AuthorDetail.objects.filter(phone=120).values('author__name')
# print(res)
# 查询作者为jason的写的书的名字
# res = models.Author.objects.filter(name='jason').values('book__title')
# print(res)
# 查询书籍为三国演义的作者的电话号码
# res = models.Book.objects.filter(title='三国演义').values('authors__authordetail__phone')
# print(res)
# 查询jason作者的手机号
# 正向
# res = models.Author.objects.filter(name='jason').values('authordetail__phone')
# print(res)
# 反向
# res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
# print(res)
# 查询出版社为东方出版社的所有图书的名字和价格
# 正向
# res = models.Publish.objects.filter(name='东方出版社').values('book__title','book__price')
# print(res)
# 反向
# res = models.Book.objects.filter(publish__name='东方出版社').values('title','price')
# print(res)
# 查询东方出版社出版的价格大于400的书
# 正向
# res = models.Publish.objects.filter(name="东方出版社",book__price__gt=400).values('book__title','book__price')
# print(res)
# 反向
# res = models.Book.objects.filter(price__gt=400,publish__name='东方出版社').values('title','price')
# print(res)
聚合查询和分组查询
# 聚合查询 aggregate
# from django.db.models import Max,Min,Count,Sum,Avg
# 查询所有书籍的作者个数
# res = models.Book.objects.filter(pk=3).aggregate(count_num=Count('authors'))
# print(res)
# 查询所有出版社出版的书的平均价格
# res = models.Publish.objects.aggregate(avg_price=Avg('book__price'))
# print(res) # 4498.636
# 统计东方出版社出版的书籍的个数
# res = models.Publish.objects.filter(name='东方出版社').aggregate(count_num=Count('book__id'))
# print(res)
# 分组查询(group_by) annotate
# 统计每个出版社出版的书的平均价格
# res = models.Publish.objects.annotate(avg_price=Avg('book__price')).values('name','avg_price')
# print(res)
# 统计每一本书的作者个数
# res = models.Book.objects.annotate(count_num=Count('authors')).values('title','count_num')
# print(res)
# 统计出每个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
# print(res)
# 查询每个作者出的书的总价格
# res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
# print(res)