前言Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
ORM是什么?:(在django中,根据代码中的类自动生成数据库的表也叫--code first) ORM:Object Relational Mapping(关系对象映射) 类名对应------》数据库中的表名 类属性对应---------》数据库里的字段 类实例对应---------》数据库表里的一行数据 obj.id obj.name.....类实例对象的属性
Django orm的优势: Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可;
一、Django连接MySQL
1、创建数据库 (注意设置 数据的字符编码) 由于Django自带的orm是data_first类型的ORM,使用前必须先创建数据库 create database day70 default character set utf8 collate utf8_general_ci;
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'day70', 'USER': 'eric', 'PASSWORD': '123123', 'HOST': '192.168.182.128', 'PORT': '3306', } }
扩展:查看orm操作执行的原生SQL语句 在project中的settings.py文件增加 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
3、修改project 中的__init__py 文件设置 Django默认连接MySQL的方式 import pymysql
pymysql.install_as_MySQLdb()
4、setings文件注册APP INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', ] 5、models.py创建表
6、进行数据迁移 6.1、在winds cmd或者Linux shell的项目的manage.py目录下执行 python manage.py makemigrations #根据app下的migrations目录中的记录,检测当前model层代码是否发生变化? python manage.py migrate #把orm代码转换成sql语句去数据库执行 python manage.py migrate --fake #只记录变化,不提交数据库操作
扩展:修改表结构之后常见报错
这个报错:因为表创建之时,新增字段既没有设置默认值,也没有设置新增字段可为空,去对应原有数据导致; 2中解决方法:
1.设置新增字段可以为空 startdate = models.CharField(max_length=255, verbose_name="任务开始时间",null=True, blank=True) Handledate = models.CharField(max_length=255, verbose_name="开始处理时间",null=True, blank=True) Handledone = models.CharField(max_length=255, verbose_name="处理完毕时间", null=True, blank=True) enddate = models.CharField(max_length=255, verbose_name="任务结束时间",null=True, blank=True) WorkTime_cost=models.CharField(max_length=255,verbose_name='工作耗时',null=True, blank=True)
2.设置新增字段默认值为 当前时间 Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now Type 'exit' to exit this prompt >>> timezone.now()
7.设置pycharm可视化MySQL
二、modles.py创建表ORM字段介绍Djan提供了很多字段类型,比如URL/Email/IP/ 但是mysql数据没有这些类型,这类型存储到数据库上本质是字符串数据类型,其主要目的是为了封装底层SQL语句;
1、字符串类(以下都是在数据库中本质都是字符串数据类型,此类字段只是在Django自带的admin中生效) name=models.CharField(max_length=32) EmailField(CharField): IPAddressField(Field) URLField(CharField) SlugField(CharField) UUIDField(Field) FilePathField(Field) FileField(Field) ImageField(FileField) CommaSeparatedIntegerField(CharField) 扩展 models.CharField 对应的是MySQL的varchar数据类型 char 和 varchar的区别 : char和varchar的共同点是存储数据的长度,不能 超过max_length限制, 不同点是varchar根据数据实际长度存储,char按指定max_length()存储数据;所有前者更节省硬盘空间;
2、时间字段 models.DateTimeField(null=True) date=models.DateField()
3、数字字段 (max_digits=30,decimal_places=10)总长度30小数位 10位) 数字: num = models.IntegerField() num = models.FloatField() 浮点 price=models.DecimalField(max_digits=8,decimal_places=3) 精确浮点
4、枚举字段 choice=( (1,'男人'), (2,'女人'), (3,'其他') ) lover=models.IntegerField(choices=choice) #枚举类型
扩展 在数据库存储枚举类型,比外键有什么优势? 1、无需连表查询性能低,省硬盘空间(选项不固定时用外键)
其他字段 db_index = True 表示设置索引 unique(唯一的意思) = True 设置唯一索引 联合唯一索引 class Meta: unique_together = ( ('email','ctime'), ) 联合索引(不做限制) index_together = ( ('email','ctime'), ) ManyToManyField(RelatedField) #多对多操作
字段参数介绍1.数据库级别生效
View Code
2、Django admin级别生效 针对 dango_admin生效的参数(正则匹配)(使用Django admin就需要关心以下参数!!))
View Code
三、ORM单表操作0、orm操作前戏orm使用方式: orm操作可以使用类实例化,obj.save的方式,也可以使用create()的形式
QuerySet数据类型介绍 QuerySet与惰性机制 所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。 QuerySet特点: <1> 可迭代的 <2> 可切片 <3>惰性计算和缓存机制
View Code
增加和查询操作 增
View Code
根据条件判断,增加?更新?
View Code
删
View Code
改
View Code
查
View Code
连表查询
View Code
1、基本操作
View Code
2、进阶操作(了不起的双下划线)利用双下划线将字段和对应的操作连接起来
View Code
3、其他操作(执行原生SQL)# 执行原生SQL 1.执行自定义SQL # from django.db import connection, connections # cursor = connection.cursor() # cursor = connections['default'].cursor() # cursor.execute("""SELECT * from auth_user where id = %s""", [1]) # row = cursor.fetchone() 2.使用extra方法 # # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) # Entry.objects.extra(where=['headline=%s'], params=['Lennon']) # Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) # Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) 3.使用raw方法 解释:执行原始sql并返回模型 说明:依赖model多用于查询 用法: book = Book.objects.raw("select * from hello_book") for item in book: print(item.title) https://www.cnblogs.com/413xiaol/p/6504856.html # F # # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1) # Q # # 方式一: # Q(nid__gt=10) # Q(nid=8) | Q(nid__gt=10) # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') # 方式二: # con = Q() # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id', 1)) # q1.children.append(('id', 10)) # q1.children.append(('id', 9)) # q2 = Q() # q2.connector = 'OR' # q2.children.append(('c1', 1)) # q2.children.append(('c1', 10)) # q2.children.append(('c1', 9)) # con.add(q1, 'AND') # con.add(q2, 'AND') # # models.Tb1.objects.filter(con)
四、ORM连表操作我们在学习django中的orm的时候,我们可以把一对多,多对多,分为正向和反向查找两种方式。 正向查找:ForeignKey在 UserInfo表中,如果从UserInfo表开始向其他的表进行查询,这个就是正向操作,反之如果从UserType表去查询其他的表这个就是反向操作。
正向连表操作总结: 所谓正、反向连表操作的认定无非是Foreign_Key字段在哪张表决定的, Foreign_Key字段在哪张表就可以哪张表使用Foreign_Key字段连表,反之没有Foreign_Key字段就使用与其关联的 小写表名; 1对多:对象.外键.关联表字段,values(外键字段__关联表字段) 多对多:外键字段.all() 反向连表操作总结: 通过value、value_list、fifter 方式反向跨表:小写表名__关联表字段 通过对象的形式反向跨表:小写表面_set().all()
应用场景: 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择) 例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。 多对多:在某表中创建一行数据是,有一个可以多选的下拉框 例如:创建用户信息,需要为用户指定多个爱好
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了 例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
1、1对多如果A表的1条记录对应B表中N条记录成立,两表之间就是1对多关系;在1对多关系中 A表就是主表,B表为子表,ForeignKey字段就建在子表; 如果B表的1条记录也对应A表中N条记录,两表之间就是双向1对多关系,也称为多对多关系;
在orm中设置如果 A表设置了外键字段user=models.ForeignKey('UserType')到B表(注意外键表名加引号) 就意味着 写在写A表的B表主键, (一列),代表B表的多个(一行)称为1对多, 查询 总结:利用orm获取 数据库表中多个数据 获取到的数据类型本质上都是 queryset类型, modle.表名.objects.all()
跨表 正操作
所以表间只要有外键关系就可以一直点下去。。。点到天荒地老 所以可以通过obj.外键.B表的列表跨表操作(注意!!orm连表操作必须选拿单个对象,不像SQL中直接表和表join就可以了) print(obj.cls.title)
foreignkey字段在那个表里,那个表里一个"空格"代表那个表的多个(一行)
class UserGroup(models.Model): """ 部门 3 """ title = models.CharField(max_length=32) class UserInfo(models.Model): """ 员工4 """ nid = models.BigAutoField(primary_key=True) user = models.CharField(max_length=32) password = models.CharField(max_length=64) age = models.IntegerField(default=1) # ug_id 1 ug = models.ForeignKey("UserGroup",null=True)
1. 在取得时候跨表
反向连表: 反向操作无非2种方式: 1、通过对象的形式反向跨表:小写表面_set().all() 2、通过value和value_list方式反向跨表:小写表名__字段
obj = UserGroup.objects.all().first() v = UserGroup.objects.values('id','title') v = UserGroup.objects.values_list('id','title')
1对多自关联( 由原来的2张表,变成一张表! )
想象有第二张表,关联自己表中的 行
代码 class Comment(models.Model): """ 评论表 """ news_id = models.IntegerField() # 新闻ID content = models.CharField(max_length=32) # 评论内容 user = models.CharField(max_length=32) # 评论者 reply = models.ForeignKey('Comment',null=True,blank=True,related_name='xxxx') #回复ID
2、 多对多:1、自己写第3张关系表 ORM多对多查询: 女士表: 男生表: 男女关系表
多对跨表操作
View Code
多对多关系表 数据查找思路 1、找到该对象
2、第3张关系表不用写(m=models.ManyToManyField(' 要关联的表') 自动生成 )
由于 DjangoORM中一个类名对应一张表,要想操作表就modles.类直接操作那张表,但使用ManyToManyField字段生成 “第三张”关系表怎么操作它呢? 答案:通过单个objd对象 间接操作
View Code
正向操作: obj.m.all()
View Code
反向操作 :obj.小写的表名_set 多对多和外键跨表一样都是 小写的表名_set
3、既自定义第三张关系表 也使用ManyToManyField('Boy')字段(杂交类型)ManyToManyField()字段创建第3张关系表,可以使用字段跨表查询,但无法直接操作第3张表, 自建第3表关系表可以直接操作,但无法通过字段 查询,我们可以把他们结合起来使用; 作用: 1、既可以使用字段跨表查询,也可以直接操作第3张关系表 2、obj.m.all() 只有查询和清空 方法
View Code
View Code
外键反向查找别名(方便反向查找)在写ForeignKey字段的时候,如果想要在反向查找时不使用默认的 小写的表名_set,就在定义这个字段的时间加related参数! related_name、related_query_name 字段=什么别名 反向查找时就使用什么别名!
反向查找: 设置了related_query_name 反向查找时就是obj.别名_set.all()保留了_set related_query_name
View Code
related_name反向查找: 设置了relatedname就是 反向查找时就说 obj.别名.all()
View Code
操作
View Code
多对多自关联(由原来的3张表,变成只有2张表)把两张表通过 choices字段合并为一张表 ‘第三张关系表’ 使用models.ManyToManyField('Userinfo')生成
特性: obj = models.UserInfo.objects.filter(id=1).first() 获取对象 1、查询第三张关系表前面那一列:obj.m select xx from xx where from_userinfo_id = 1 2、查询第三张关系表后面那一列:obj.userinfo_set
View Code
查找方法
View Code
多对多自关联特性:
ManyToManyField生成的第三张表
五、浅谈ORM查询性能
View Code
六、分组和聚合查询1、aggregate(*args,**kwargs) 聚合函数 通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
View Code
2、annotate(*args,**kwargs) 分组函数
View Code
七、F查询与Q查询仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:
1、F 可以获取对象中的字段的属性(列),并对其进行操作; from django.db.models import F,Q #F 可以获取对象中的字段的属性(列),并且对其进行操作; models.Book.objects.all().update(price=F('price')+1) #对图书馆里的每一本书的价格 上调1块钱
2、Q多条件组合查询 Q()可以使orm的fifter()方法支持, 多个查询条件,使用逻辑关系(&、|、~)包含、组合到一起进行多条件查询;
语法: fifter(Q(查询条件1)| Q(查询条件2)) fifter(Q(查询条件2)& Q(查询条件3)) fifter(Q(查询条件4)& ~Q(查询条件5)) fifter(Q(查询条件6)| Q(Q(查询条件4)& ~ Q(Q(查询条件5)& Q(查询条件3)))包含
View Code
注意:Q查询条件和非Q查询条件混合使用注意,不包Q()的查询条件一点要放在Q(查询条件)后面
八、Django自带ContentType表首先声明本文介绍的ContentType不是http协议中请求头里Content Type,而是Django程序启动后自带的一张表;
setings.py配置文件
1、ContentType表内容介绍 ContentType表记录了Django程序的所有APP下model中的表名、和所在app的名称;
2、应用场景: 2.1 通过ContentType中的app名称和表名,查找到Django model中所有表;
View Code;
2.2 解决 1张表 同时 其他N张表建立外键,并且多个外键中只能选择1个,关系的复杂问题
场景1:你是一家在线教育的DBA,现有N种优惠券,每1种优惠券怎么分别对应 N门课程中的一1门课程,怎么设计表结构呢?
View Code
场景2 :学生 学习成绩如何要奖惩、 作业写得如何要奖惩、学习进度如何要奖惩、。。。。。。学生各种行为都要奖惩怎么设计表结构?
View Code
3、content type 操作
model
视图
3.1 GenericForeignKey 创建 给学位课1,创建优惠券100
方式1
方式2
model
视图
3.2 GenericRelation 查询 当前课程都有哪些优惠券?
model
视图
九、补充oder_by(-id):按照某种规则排序
exclude(字段):字段获取数据时排除
View Code
二龙湖浩哥:http://www.cnblogs.com/yuanchenqi/articles/6811632.html#3763280 银角大王:http://www.cnblogs.com/wupeiqi/articles/5246483.html
|
|
来自: 昵称58214903 > 《待分类》