django orm插入一条_Django之ORM操作

前言

Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架

到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:

创建数据库,设计表结构和字段

使用 MySQLdb 来连接数据库,并编写数据访问层代码

业务逻辑层去调用数据访问层执行数据库操作

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;

2、修改project中的settings.py文件中设置  连接 MySQL数据库(Django默认使用的是sqllite数据库)

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、无需连表查询性能低,省硬盘空间(选项不固定时用外键)

2、在modle文件里不能动态增加(选项一成不变用Django的choice)

其他字段

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表去查询其他的表这个就是反向操作。

一对多:models.ForeignKey(其他表)

多对多:models.ManyToManyField(其他表)

一对一:models.OneToOneField(其他表)

正向连表操作总结:

所谓正、反向连表操作的认定无非是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类型,

类似于列表,

内部有3种表现形式(对象,字典,列表)

modle.表名.objects.all()

modle.表名.objects.values()

modle.表名.objects.values()

跨表

正操作

所以表间只要有外键关系就可以一直点下去。。。点到天荒地老

所以可以通过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. 在取得时候跨表

q = UserInfo.objects.all().first()

q.ug.title

2. 在查的时候就跨表了

UserInfo.objects.values('nid','ug_id')

UserInfo.objects.values('nid','ug_id','ug__title')   #注意正向连表是  外键__外键列 反向是小写的表名

3. UserInfo.objects.values_list('nid','ug_id','ug__title')

反向连表:

反向操作无非2种方式:

1、通过对象的形式反向跨表:小写表面_set().all()

2、通过value和value_list方式反向跨表:小写表名__字段

1. 小写的表名_set 得到有外键关系的对象

obj = UserGroup.objects.all().first()

result = obj.userinfo_set.all() [userinfo对象,userinfo对象,]

2. 小写的表名 得到有外键关系的列 #因为使用values取值取得是字典的不是对象,所以需要 小写表名(外键表)__

v = UserGroup.objects.values('id','title')

v = UserGroup.objects.values('id','title','小写的表名称')

v = UserGroup.objects.values('id','title','小写的表名称__age')

3. 小写的表名 得到有外键关系的列

v = UserGroup.objects.values_list('id','title')

v = UserGroup.objects.values_list('id','title','小写的表名称')

v = UserGroup.objects.values_list('id','title','小写的表名称__age')

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.通过第三张关系表 正向操作 找到 和该对象有关系对象

总结(只要对象1和对象2 中间有关系表建立了关系; 对象1反向操作 到关系表 ,关系表正向操作到对象2,反之亦然

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

select xx from xx where to_userinfo_id = 1

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

你可能感兴趣的:(django,orm插入一条)