模型层
目录
模型层:
ORM查询
ORM中常用字段和参数:
1.int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列 (AutoField)
2.一个整数类型,范围在 -2147483648 to 2147483647(用字符串存储)(IntegerField)
3.字符类型,必须提供max_length参数, max_length表示字符最大长度(CharField)
4.日期字段,日期格式 YYYY-MM-DD (DateField)\
5.日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] (DateTimeField)
6.表示某个字段可以为空。 (null)
7.设置为unique=True 则该字段在此表中必须是唯一的 。(unique)
8.db_index=True 则代表着为此字段设置索引。
9.为该字段设置默认值。 (default)
10.配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库 (auto_now_add)
11.配置上auto_now=True,每次更新数据记录的时候会更新该字段 (auto_now : 仅仅记载最新的记录)
12.EmailField() : 数据类型是 varchar(254)
表之间的关系:
表之间的关联 : 外键 (ForeignKey)
1.外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。
2.ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
参数:to ; 设置要关联的表
to_file: 设置要关联表的字段
on_delete:删除关联表中的数据时,当前表与其关联的行的行为。
models.CASCADE : 删除关联数据,与之关联也删除!
db_constraint : 是否在数据库中创建外键约束,默认为True。
定义新字段:
自定义新的字段:
1.必须要有max_length
2.返回值必须为字符串
class xxCharField(models.Fiels):
'''自定义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): #返回字符类型
return 'char(%s)' %self.max_length
#创表(运用自定义的字段类)
class Class(models.Model):
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
配置测试脚本
配置orm操作数据库(mysql)的测式文件:
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
import django
django.setup()
from app01 import models
models.Books.objects.all()
注意:
1.from app01 import models放置在建立测试脚本搭建完毕后
2.新建一个.py文件,要导入以上代码
3.在orm测式文件内部对数据进行操作
日志记录:
记录数据库操作:
--》放置在settings
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
orm对表内数据的操作:
查找数据:
--》 res = models.Books.objects.filter(pk=1)
# pk :会自动帮你查找到当前表的主键字段(指代主键字段)
# filter 查询出来的结果是一个Queryset对象:
1.只要是queryset对象就可以无限制的调用queryset的方法
res = models.Books.objects.filter(pk=1).filter().....
2.只要是queryset对象就可以点query查看当前结果内部对应的sql语句
res = queryset_obj.query ==== > sql 语句
创建数据:
1.create() :
book_obj = models.Books.objects.create(title='三国演义',publish_date='2019-11-11') #输入时间格式 :可以输入字符串
# ctime = date.today()
book_obj = models.Books.objects.create(title='三国演义',publish_date=ctime)
2.利用对象的绑定方法:
book_obj = models.Books(title='西游记',publish_date='ctime)
book_obj.save()
修改数据:
1.利用queryset方法:
models.Books.objects.filter(pk=1).update(price=444)
2,利用对象:
book_obj = models.Books.objects.get(pk=1)
book_obj.price = 222
book_obj.save()
注意 : 利用对象的修改 内部其实是重头到位将数据的所有字段都重新写一遍(先删再创一个新的)
删除数据:
1.利用queryset方法 delete()
models.Books.objects.filter(pk=3).delete()
2,对象方法
book_obj = models.Books.objects.get(pk=3)
book_obj.delete()
get 与 filter 的区别:
区别:
1.filter获取到的是一个queryset对象 类似于一个列表
2.get获取到的直接就是数据对象本身
当条件不存在的情况下:
filter不报错直接返回一个空
get直接报错 所以不推荐使用get方法
单表查询13条方法
orm语句的查询 :
惰性查询,只有当你真正要使用数据的时候才会执行orm语句
1.all() : 查询匹配的所有数据 --》 返回 QuerySet对象
eg: res = models.Books.objects.all()
2.filter() : 筛选 (类似于 where 条件) -返回 QuerySet对象
eg: res = models.Books.object.filter(pk=1)
3.get() : 筛选 返回数据对象本身 查询条件必须是唯一的
eg: res = models.Books.objects.get(title='西游记')
4.first() : 取queryset中第一个数据对象 返回数据对象
eg: res = models.Books.objects.filter(pk=1).first()
5.last() 取queryset中最后一个数据对象 数据对象
eg: res = models.Books.objects.filter(pk=1).last()
6. count() 统计数据的个数(表记录的个数) 数字
eg: num = models.Books.objects.count()
7.values() 获取数据对象中指定的字段的值 多个 queryset 列表套字典
eg: res = models.Books.objects.values('title','price')
<QuerySet [{'title': '三国演义', 'price': Decimal('222.66')}
8.values_list() 获取数据对象中指定的字段的值 多个 queryset 列表套元祖
eg: res = models.Books.objects.values_list('title','price')
<QuerySet [('三国演义', Decimal('222.66'))
9.order_by() 按照指定的字段排序 # 默认是升序
eg: res = models.Books.objects.all().order_by('price')
# 降序 字段前面加负号
res1 = models.Books.objects.all().order_by('-price')
10.reverse() 颠倒顺序 前提是跌倒的对象必须有顺序(排序之前才能颠倒)
res1 = models.Books.objects.all().reverse()
11.exclude() 排除什么什么之外 queryset对象
res = models.Books.objects.all().exclude(title='三国演义')
12.exists() 判断查询结果是否有值 返回结果是一个布尔值
res = models.Books.objects.filter(pk=1).exists()
13..distinct() 去重操作 去重的前提:表记录数据必须是完全相同的情况下
res = models.Books.objects.values('title','price').distinct()
注意 :
1.去重必须是一条表记录内所有的数据都一样(包括主键)
2.能对帅选过后的数据进行去重
双下划线查询方法:
-->范围查询
大于 :xx_gt / 小于 : xx_lt
大于等于: xx__gte 缺陷 :python 对小数不敏感(识别有误)
小于等于: xx__lte
eg: res = models.Books.objects.filter(price__lte=500)
或者..或者是 :xx__in=[]
eg: res = models.Books.objects.filter(price__in=[222,444,500])
在...到...之间 : xx__range = (,) 顾头顾尾
eg: res = models.Books.objects.filter(price__range=(200,800))
查询日期: publish_date__year'
eg: res = models.Books.objects.filter(publish_date__year='2019')
模糊查询
MySQL中的模糊查询
-->关键字 like
模糊匹配的符号:
%:匹配任何个数的任意字符
_:匹配一位任意的字符
以....开头: __startswith
res = models.Books.objects.filter(title__startswith='三')
以....结尾: __endswith
res = models.Books.objects.filter(title__endswith='1')
包含...在其中:__contains
res = models.Books.objects.filter(title__contains='p') # 默认区分大小写
res = models.Books.objects.filter(title__icontains='p') # 忽略大小写 加i
一对多数据的增删改查:
增:
第一种 :models.Book.objects.create(title='三国演义',ublish_id=1)
#直接传表里面的实际字段 跟数据主键值 publish_id
第二种 :publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',publish=publish_obj) # 传虚拟字段 跟数据对象即可
改:
第一种 :models.Book.objects.filter(pk=1).update(publish_id=2)
第二种 :publish_obj = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
删:
models.Publish.objects.filter(pk=1).delete()
# 默认就是级联删除 级联更新 (关联表一起变化)
多对多数据的增删改查:
--》创建第三张表进行操作。
增: add()
把指定的model对象添加到第三张关联表中。
添加对象:
>>> author_objs = models.Author.objects.filter(id__lt=3)
>>> models.Book.objects.first().authors.add(*author_objs)
添加id:
>>> models.Book.objects.first().authors.add(*[1, 2])
改 : set()
更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置
-->括号内的数据必须要是可迭代对象!!!
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.set([2, 3])
删 : remove() / clear()
从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系)
>>> book_obj = models.Book.objects.first()
>>> book_obj.authors.remove(3)
清空 删除某个数据在第三张表中的所有记录: clear()
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.clear()
跨表设计
正反向查询 ;
正 向查询 :有外键查的一边,查询另一边 --》查询按字段
反 向查询 :没有外键的一边, 查询拥有外键一边 ---》按表明小写
反向:对象_set ---> 查询数据有多个 / 一个就不加
基于对象的跨表查询:
--》 子查询 分步操作
# 基于对象的跨表查询 子查询 分步操作
# 1.查询书籍主键为2的出版社名称
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish) # 出版社对象
print(book_obj.publish.name)
# 2.查询书籍主键为4的作者姓名
book_obj = models.Book.objects.filter(pk=4).first()
print(book_obj.authors) # app01.Author.None
print(book_obj.authors.all())
# 3.查询作者是jason的手机号码
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail)
print(author_obj.author_detail.phone)
# 4.查询出版社是东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# print(publish_obj.book_set) # app01.Book.None
print(publish_obj.book_set.all())
# 5.查询作者是jason写过的书籍
author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.book_set) # app01.Book.None
print(author_obj.book_set.all()) # app01.Book.None
# 6.查询手机号是120的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
print(author_detail_obj.author)
print(author_detail_obj.author.email)
基于双下滑先的跨表查询
基于双下滑先的跨表查询:
--》联表操作
# 1.查询书籍pk为2的出版社名称
# 正向
res = models.Book.objects.filter(pk=2).values('publish__name') # 写外键字段就相当于已经跨到外键字段所关联的表
# 你想要改表的哪个字段信息 你只需要加__获取即可
print(res)
# 反向
res = models.Publish.objects.filter(book__pk=2).values('name')
print(res)
# 2.查询书籍pk为2的作者姓名和邮箱
res = models.Book.objects.filter(pk=2).values('authors__name','authors__email')
print(res)
res = models.Author.objects.filter(book__pk=2).values('name','email')
print(res)
# 3.查询作者是egon的家庭地址
res = models.Author.objects.filter(name='egon').values('author_detail__addr')
print(res)
res = models.AuthorDetail.objects.filter(author__name='egon').values('addr')
print(res)
# 4.查询出版社是东方出版社出版过的书的名字
res = models.Publish.objects.filter(name='东方出版社').values('book__title')
print(res)
res = models.Book.objects.filter(publish__name='东方出版社').values('title')
print(res)
# 查询书籍pk是2的作者的手机号
res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
print(res)
res = models.Author.objects.filter(book__pk=2).values('author_detail__phone')
print(res)
小技巧
models + 表名 --》 查询以表名为基表 !!
什么时候需要加all ???
1.当正向查询点击外键字段数据有多个的情况下 需要.all()
2.app01.Author.None 一旦看到该结果 只需要加.all()即可
mysql : 链表操作(
inner join
left join
right join
union #两边表都没有
)
什么时候反向查询的时候表名小写需要加_set??
一对多表关系
多对多表关系
一对一表关系不需要加_set
技巧:在写orm语句的时候跟你写sql语句一样 不要想着一次性写完,查一点再写一点