Django ORM 操作
ORM
- ORM (object Relational Mapping)
对象和关系型数据库的一个映射 同过操作对象的方式操作数据库的内容
-
对应关系
类 ___> 表
对象 ___> 记录 数据行
属性 ___> 字段
-
ORM的操作:
-
查询
1. models.Publisher.objects.all() # 查询所有的数据 ——》 QuerySet 对象列表 2. models.Publisher.objects.get() # 获取满足条件的一个对象 ——》 单独的对象 3. models.Publisher.objects.filter() # 获取满足条件的所有对象 ——》对象列表 4. models.Publisher.objects.all().order_by('id') # 排序 —— 》 对象列表 5. pub_obj.pk ——》 主键 6. pub_obj.name 7. 外键 1. book_obj.publisher ——》 关联的对象 2. book_obj.publisher_id ——》从book表中获取关联对象的ID 3. book_obj.publisher.name ——》 关联的对象的属性 8. 多对多 1. author_obj.books ——》 管理对象 2. author_obj.books.all() ——》 关联的所有的对象 对象列表 3. book_obj.author_set ——》管理对象、
-
增加
1. models.Publisher.objects.create(name='xxx') ——》 对象 2. 外键 1. models.Book.objects.create(title='xxx',publisher=pub_obj) 2. models.Book.objects.create(title='xxx',publisher_id=pub_obj.id) 3. 多对多 1. models.Author.objects.create(name='xxxx') ——》 author_obj 2. author_obj.books.set([多个要关联对象的id,]) 3. author_obj.books.set([多个要关联对象,])
-
删除
1. models.Author.objects.get(id=1).delete() 2. models.Author.objects.filter(id=1).delete()
-
修改
1. 1. pub_obj.name = 'new_xxxx' 2. pub_obj.save() 3. 外键 1. book_obj.title = 'xxxx' 2. book_obj.publisher = pub_obj 或者 book_obj.publisher_id = pub_obj .id 3. book_obj.save() 4. 多对多 1. author_obj.name = 'new_name' 2. author_obj.save() 3. author_obj.books.set([多个要关联对象,]) author_obj.books.set([多个要关联对象的id,])
-
具体的操作
from app01 import models
# 获取所有数据
models.User.objects.all() # __> QuerySet 对象列表
# 获取单个对象 获取不到数据或者拿到多条数据就报错
models.User.objects.get(name='alex',pwd='111') # __> 对象
# 获取满足条件的所有对象
models.User.objects.filter(name='alex',pwd='111') # __> QuerySet 对象列表
字段和字段的参数
1.字段和字段的参数
常用的:
AutoField # 自增字段
参数:
primary_key=True # 主键
IntegerField # 整数类型
参数:
blank=True # admin中显示
BooleanField # bool类型
参数:
choices((1,'男'),(0,'女')) 只能有两个值
0 为存储的值 男女为显示的内容
CharField # varchar 类型
参数:
max_length=32 # 必填 最大长度
TextField # 文本类型
DateTimeField # 时间类型
参数:
auto_new_add=True # 新增时自动保存当前时间
auto_new=True # 修改时自动保存当前时间
DecimalField # 小数类型
参数:
max_digits=5 # 小数总长速度
decimal_places=2 # 小数位长度
ForeignKey('表名',) # 外键
OneTuoOneField('表名',) # 等同于外键关联自己
参数:
related_name='books', # 用于反向查询
related_query_name='book'
ManyToManyField('表名',) # 多对多
参数:
related_name='books', # 用于反向查询
related_query_name='book' # 用于反向查询
其他参数:
db_column='usrname' # 修改数据库中的列名 显示
verbose_name="用户名" # admin中文提示
black=True # 校验时可以为空
null=True # 存储时可以为空
unique=true # 字段唯一
default='默认值' # 为空时提供默认值
自定义 Char 类型
class MyCharField(models.Field):
"""
自定义的char类型的字段类
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为max_length指定的值
"""
return 'char(%s)' % self.max_length
使用:
phone = MyCharField(max_length=11, )
class Meta:
# 写在model 类中
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "person"
# admin中显示的表名称
verbose_name = '个人信息'
# verbose_name加s
verbose_name_plural = '所有用户信息'
# 排序 升序排列,先按照index排序 如果相等按照id排序 倒序排列 加 -
ordering = ('index', 'id')
# # 联合索引
# index_together = [
# ("pub_date", "deadline"), # 应为两个存在的字段
# ]
#
# # 联合唯一索引
# unique_together = (("driver", "restaurant"),) # 应为两个存在的字段
查询的方法(13个)
1. models.Book.objects.all() # 获取到所有的书籍对象,结果是对象列表
2. models.Book.objects.get(条件) # 获取符合条件的对象
3. models.Book.objects.filter(条件) # 筛选所有符合条件的,结果是对象列表
4. models.Book.objects.exclude(条件) # 筛选出所有不符合条件的,结果是对象列表
5. models.Book.objects.all().values( ) # 字典列表,[ {id:1,name:20} , {id:2,name:18} ]
values(‘id’)括号内不指定时显示全部,如指定则只显示指定的,[ {id:1} , {id:2,} ]
6. models.Book.objects.all().values_list( ) # 元组列表,[ (1,20) , (2,18) ]同上,指定时显示指定内容
7. models.Book.objects.all().order_by(‘id’) # 按照id升序就行排列
models.Book.objects.all().order_by(‘-id’) # 按照id降序就行排列
models.Book.objects.all().order_by(‘age’ , ‘-id’) # 先按age升序,age相同的按id进行降序排列
8. models.Book.objects.all().order_by(‘id’).reverse() # 对结果反转; 注意reverse前必须排序,
否则reverse无效; 或在model.py文件中Book类中的Meta中指定ordering=(‘id’ , )注意逗号必须有
9. distinct(): # 去重,当获取到的结果Queryset列表中同一对象出现多次时去重,只留一个
10. models.Book.objects.all().count() # 计数,可统计结果个数,如对Queryset内元素数进行统计.
11. models.Book.objects.all().first() # 获取结果中的第一条,即使前面结果列表为空,也不会报错
12. models.Book.objects.filter().last() # 获取结果中的最后一条
13.models.Book.objects.filter().exists() # 判断Queryset列表是否有东西,结果为True或False;
小结:
返回对象列表(Queryset)的方法有:
all() filter() ordey_by() exclude() values() values_list() reverse() distinct()
返回单个对象的方法有:
first() last() get() create()创建一个对象,且返回刚创建的对象
判断布尔值的有:
exists()
返回数字的有:
count()
建立 数据库查询 orm操作
- modle 表结构
from django.db import models
class MyCharField(models.Field):
"""
自定义的char类型的字段类
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为max_length指定的值
"""
return 'char(%s)' % self.max_length
class Person(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, db_column='username', verbose_name='姓名')
age = models.IntegerField(null=True, blank=True, verbose_name='年龄')
# birth = models.DateTimeField(auto_now_add=True) # 新增的时候保存当前的时间
birth = models.DateTimeField(auto_now=True) # 每次修改的时候保存当前的时间
phone = MyCharField(max_length=11, )
gender = models.BooleanField(choices=((0, '男'), (1, '女')))
def __str__(self):
return "<Person object: {}-{}>".format(self.pk, self.name)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "person"
# admin中显示的表名称
verbose_name = '个人信息'
# verbose_name加s
verbose_name_plural = '所有用户信息'
ordering = ('id',)
class Publisher(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2) # 000.00 999.99
sale = models.IntegerField()
kucun = models.IntegerField()
publisher = models.ForeignKey('Publisher', related_name='books', related_query_name='book', null=True)
def __str__(self):
return self.title + str(self.pk)
class Author(models.Model):
name = models.CharField(max_length=32)
books = models.ManyToManyField('Book',)
在setting 中配置 查看配置 显示查询语句
import django
django.setup()
from app01 import models
# all() 获取所有的数据 对象列表
ret = models.Person.objects.all()
# filter() 获取所有满足条件的所有对象 对象列表
ret = models.Person.objects.filter(id=1)
# get() 获取一个对象 没有或者是多个的时候报错
ret = models.Person.objects.get(id=1)
# exclude 获取不满足条件的所有对象 对象列表
ret = models.Person.objects.exclude(id=1)
# values 获取对象的字段名和值 [ {},{} ]
# 不指定字段名 获取所有字段的名和值
# 指定字段名 获取指定字段的名和值
ret = models.Person.objects.all().values('name','id')
# for i in ret:
# print(i,type(i))
# values_list 获取对象的值 [ (),() ]
# 不指定字段名 获取所有字段的值
# 指定字段名 获取指定字段值
ret = models.Person.objects.all().values_list('id','name')
# for i in ret:
# print(i,type(i))
# order_by 排序 默认升序 加- 降序 指定多个进行排序
ret = models.Person.objects.all().order_by('age','id')
# reverse() 给已经排好序的结果倒叙排序
ret = models.Person.objects.all().order_by('age','id').reverse()
ret = models.Person.objects.all().reverse()
# distinct() 去重
# count 计数
ret = models.Person.objects.all().count()
# first() last 取第一个 最后一个对象
ret = models.Person.objects.filter(id=100).first()
# exists() 判断数据是否存在
ret = models.Person.objects.filter(id=1).exists()
单表的双下划线
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
ret = models.Person.objects.filter(id=1)
ret = models.Person.objects.filter(id__gt=1) # greater than
ret = models.Person.objects.filter(id__gte=1) # greater than equal
ret = models.Person.objects.filter(id__lt=3) # less than
ret = models.Person.objects.filter(id__lte=3) # less than equal
ret = models.Person.objects.filter(id__gt=1, id__lt=3)
ret = models.Person.objects.filter(id__range=[1, 3]) # 范围 左右都包含
ret = models.Person.objects.filter(id__in=[1, 3]) #
ret = models.Person.objects.filter(name__contains='alex') # 包含 like
ret = models.Person.objects.filter(name__icontains='alex') # 包含 like
ret = models.Person.objects.filter(name__startswith='a') # 以什么开头
ret = models.Person.objects.filter(name__istartswith='a') # 以什么开头 忽略大小写
ret = models.Person.objects.filter(name__endswith='x') # 以什么结尾
ret = models.Person.objects.filter(name__iendswith='X') # 以什么结尾 忽略大小写
ret = models.Person.objects.filter(birth__year=2018)
ret = models.Person.objects.filter(birth__contains='2018-12')
外键的操作
# 基于对象的查询
# 正向 有外键的一侧 查关联的对象
book_obj = models.Book.objects.get(id=1)
book_obj.publisher 关联的对象
# print(book_obj.publisher) # 关联的对象
# print(book_obj.publisher_id) # 关联的对象的id
# print(book_obj.publisher.id) # 关联的对象的id
# 反向查询 被关联的对象 查有外键的一侧
# pub_obj = models.Publisher.objects.get(id=1)
# print(pub_obj.name)
不指定related_name
pub_obj.book_set 管理对象
pub_obj.book_set.all()
指定related_name = ‘books’
pub_obj.books 管理对象
# 不指定 related_name='books'
# print(pub_obj.book_set,type(pub_obj.book_set))
# print(pub_obj.book_set.all())
# 指定related_name='books'
# print(pub_obj.books,type(pub_obj.books))
# print(pub_obj.books.all())
# 基于字段的查询
# ret = models.Book.objects.filter(publisher__name='老男孩出版社')
# 不指定related_name
# ret = models.Publisher.objects.filter(book__title='太亮教开车')
# 指定related_name
# ret = models.Publisher.objects.filter(books__title='太亮教开车')
# 指定related_query_name='book'
# ret = models.Publisher.objects.filter(book__title='太亮教开车')
# 外键字段可以为null 才有remove和clear 只能写对象
pub_obj = models.Publisher.objects.get(id=1)
# pub_obj.books.remove(models.Book.objects.get(id=1))
# pub_obj.books.clear()
pub_obj.books.create(title='太亮的产后护理')
多对多的操作
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
# 基于对象的查询
# 正向
author_obj = models.Author.objects.get(id=2)
#
# print(author_obj.books,type(author_obj.books))
# print(author_obj.books.all())
# 反向
book_obj = models.Book.objects.get(id=1)
# 不指定related_name='authors'
# print(book_obj.author_set.all())
# 指定related_name='authors'
# print(book_obj.authors.all())
# set 设置多对多关系
# author_obj.books.set([])
# author_obj.books.set([1,2,3]) # 要关联对象的ID [ 对象的id,对象的id]
# author_obj.books.set(models.Book.objects.all()) # 要关联对象 [ 对象,对象]
# add 添加多对多的关系
# author_obj.books.add(1) # 要关联对象的ID
# author_obj.books.add(models.Book.objects.get(id=2)) # 要关联对象
# remove() 删除多对多的关系
# author_obj.books.remove(1) # 要关联对象的id
# author_obj.books.remove(models.Book.objects.get(id=2)) # 要关联对象
# clear() # 清空当前对象的多对多的关系
# author_obj.books.clear()
# create()
# author_obj.books.create(title='太亮教抛光',)
# update() 更新字段
# author_obj.books.update(title='太亮教抛光',)
book_obj.authors.create(name='alex')
聚合 和分组
Max, Min, Sum, Avg, Count
aggregate 聚合
annotate 分组
mport os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
from django.db.models import Max, Min, Sum, Avg, Count
#aggregate 聚合
ret = models.Book.objects.aggregate(max=Max('price')) # { }
# annotate 分组
# 统计每一本书的作者个数
ret = models.Book.objects.all().annotate(count=Count('author')).values('count')
# 统计出每个出版社买的最便宜的书的价格
# 方法一
ret = models.Publisher.objects.all().annotate(Min('book__price')).values()
# for i in ret:
# print(i)
# 方法二
ret = models.Book.objects.values('publisher__name').annotate(min=Min('price')).values('min')
# for i in ret:
# print(i)
# 统计不止一个作者的图书
ret = models.Book.objects.annotate(count=Count('author')).filter(count__gt=1)
ret = models.Book.objects.annotate(count=Count('author')).order_by('-count')
print(ret)
# 查询各个作者出的书的总价格
ret = models.Author.objects.annotate(Sum('books__price')).values()
for i in ret:
print(i)
F 和 Q
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
from django.db.models import F
# ret= models.Book.objects.filter(kucun__gt=F('sale')).values()
# for i in ret:
# print(i)
# models.Book.objects.all().update(sale=F('sale')*2)
# obj = models.Book.objects.filter(id=1).first()
#
# obj.sale = 60
# obj.save()
from django.db.models import Q
ret = models.Book.objects.filter(Q(~Q(id__lt=3) | Q(id__gt=5))&Q(id__lt=4))
print(ret)
事物
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
from django.db import transaction
try:
with transaction.atomic():
res = models.Publisher.objects.filter(name='新华出版社1').select_for_update() # 加锁
res.update() # 释放锁
models.Publisher.objects.create(name='新华出版社1')
int('aaa')
models.Publisher.objects.create(name='新华出版社2')
models.Publisher.objects.create(name='新华出版社2')
except Exception as e:
print(e)
性能
-
性能相关
-
能用values,别用对象进行查询
-
select_related 主动连表 一次查询
-
prefetch_related 子查询 两次查询
-
only (只拿某些字段) defer(排除某些字段)
QuerySet
-
使用原生sql的 方法 :
-
raw
# row方法:(掺杂着原生sql和orm来执行的操作) res = CookBook.objects.raw('select id as nid from epos_cookbook where id>%s', params=[1, ]) print(res.columns) # ['nid'] print(type(res)) # <class 'django.db.models.query.RawQuerySet'> # 在select里面查询到的数据orm里面的要一一对应 res = CookBook.objects.raw("select * from epos_cookbook") print(res) for i in res: print(i.create_date) print(i) res = CookBook.objects.raw('select * from epos_cookbook where id>%s', params=[1, ]) # 后面可以加参数进来 print(res) for i in res: # print(i.create_date) print(i)
-
extra
# (1,2) 必须两个以上 # res = CookBook.objects.extra(select={"aaa": "cook_type = 1"}, where=['id in (1,2)', ]).values() res = CookBook.objects.extra(select={"aaa": "cook_type = 1"}, where=['id in (1,2)', ]) print(res) # <QuerySet [<CookBook: 鱼香肉丝>, <CookBook: 水煮鱼>]> for r in res: print(r)
-
connections (最原生)
from django.db import connection, connections # 需要配置数据库 # cursor=connection['default'].cursor() cursor = connection.cursor() # 不传参数的情况 cursor.execute("""select * from epos_cookbook""") # 为原生sql语句设置参数的情况 # cursor.execute("""select * from epos_cookbook where id=%s""",[2,]) # 2 是 id # cursor.execute("""select * from api_userinfo where id=%s"""%1) # 防止注入攻击 cursor.execute("select * from epos_cookbook where id=%s", params=[1, ]) # row=cursor.fetchone() # row=cursor.fetchmany() row = cursor.fetchall() ##拿到全部的数据 print(row)
from django.db import connection cursor=connection.cursor() # 插入操作 cursor.execute("insert into hello_author(name) values('钱钟书')") # 更新操作 cursor.execute("update hello_author set name='abc' where name='bcd'") # 删除操作 cursor.execute("delete from hello_author where name='abc'") # 查询操作 cursor.execute("select * from hello_author") raw=cursor.fetchone() # 返回结果行游标直读向前,读取一条 cursor.fetchall() # 读取所有
分页
from django.core.paginator import Paginator, Page # 导入模块
current_pagnum = 2
user_list = CookBook.objects.all().values()
paginator = Paginator(user_list, 1)
print(paginator.per_page)
# 创建一个对象paginator,又有这是一个对象,所以可以通过点“.”来调用一些功能
# per_page: 每页显示条目数量
# count: 数据总个数
# num_pages:总页数
# page_range:总页数的索引范围,如: (1,10),(1,200)
# page: page对象
posts = paginator.page(number=current_pagnum) # 这个num就是现实当前第几页
# has_next 是否有下一页
# next_page_number 下一页页码
# has_previous 是否有上一页
# previous_page_number 上一页页码
# object_list 分页之后的数据列表
# number 当前页
# paginator paginator对象
print(posts.object_list)