ORM常用操作
ORM初级简单操作
- 可以操作数据表、数据行,不能建库、删库。
不含外键的表操作
-
查询表内容
# 获取表中所有的数据 # ret是 QuerySet 对象列表 【对象】 ret = models.User.objects.all() # 获取一个对象(有且唯一) # 获取不到或者获取到多个对象会报错 obj = models.User.objects.get(username='alex') # 获取满足条件的对象 ret = models.User.objects.filter(username='alex',password='dasb') # QuerySet 对象列表,可获取用户名相同的内容
-
增加数据
obj = models.创建表的类名.objects.create(表字段名=publisher_name) # obj 是创建的数据对象 # obj.字段名=该字段内创建数据的内容 如:增加数据name = 'xiaoqi' obj.name = 'xiaoqi'
-
删除数据
obj_list = models.创建表的类名.objects.filter(pk=pk) # 获取对象列表 obj_list.delete() obj = models.Publisher.objects.get(pk=pk) # 获取指定行 对象 obj.delete()
-
编辑数据
# 修改数据 obj.name = publisher_name obj.save() # 保存数据到数据库中 # 修改数据 obj.name = publisher_name obj.save(update=['name']) # 指定更新字段
含外键的表操作
-
例:出版社与图书管理(图书管理多,多的设置外键,关联出版社)
-
查询
#########查询注意事项############ all_books = models.Book.objects.all() for book in all_books: print(book.title) print(book.pub,type(book.pub)) # ——> 所关联的出版社对象 # 注:书籍直接点外键,book.pub是先到book表中获取外键pub_id的内容,然后通过pub_id去出版社表中获取对应的数据,封装成一个对象。相当于做了两次查询 print(book.pub.pk) # 查id 多一次查询 print(book.pub_id) # 直接在book表中查出的pub_id,只查询id推荐使用此方法。 print(book.pub.name) print("*"*32)
-
新增
models.Book.objects.create(title=book_name,pub=出版社的对象) # pub是对应出版社信息的对象 models.Book.objects.create(title=book_name,pub_id=pub_id) # pub_id直接对应book表的外键值
-
删除
pk = request.GET.get('id') # 获取到id models.Book.objects.filter(pk=pk).delete()
-
编辑数据
# 修改数据 book_obj.title = book_name # book_obj.pub_id = pub_id book_obj.pub = models.Publisher.objects.get(pk=pub_id) book_obj.save()
多对多表结构
-
设计表结构
########django帮我们生成第三张表######## ########多对多表结构创建######### 作者与书的关系,一个作者写多本书,一本书可由多个人共同完成 class Author(models.Model): name = models.CharFiled(max_length = 32) books = models.ManyToManyField('Book') # 多对多,作者表与Book表之间关系 第三张表名 app名_author_books
###############自己创建第三张表############# class AuthorBook(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE) book = models.ForeignKey(Book, on_delete=models.CASCADE) date = models.DateField()
######自建的表和 ManyToManyField 联合使用######## class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField('Book',through='AuthorBook') # 不在Author表中生产字段,生产第三张表 class AuthorBook(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE) book = models.ForeignKey(Book, on_delete=models.CASCADE) date = models.DateField()
-
查询
obj_list = models.Author.objects.all() # 获取Author QuerySet 对象列表<QuerySet [<Author: Author object>....]> for obj in obj_list: # 循环获取每行数据的对象 Author object <class 'app01.models.Author'> print(obj, type(obj)) print(obj.author_name, type(obj.author_name)) # 获取对应行的author_name字段的值 mjj <class 'str'> print(obj.books, type(obj.books)) # 关系管理对象app01.Book.None print(obj.books.all(),type(obj.books.all())) # 获取Book表的QuerySet对象列表 <QuerySet [<Book: Book object>, <Book: Book object>]>
-
展示
# 展示作者 def author_list(request): # 查询所有的作者 all_authors = models.Author.objects.all() return render(request,'author_list.html',{'all_authors':all_authors})
# 写模板 {% for author in all_authors %} <tr> <td>{{ forloop.counter }}</td> <td>{{ author.pk }}</td> <td>{{ author.name }}</td> <td> {% for book in author.books.all %} {% if forloop.last %} 《{{ book.title }}》 {% else %} 《{{ book.title }}》、 {% endif %} {% endfor %} </td> </tr> {% endfor %}
-
增加
all_book = models.Book.objects.all() # 获取Book表中对象列表 book_name = request.POST.getlist('book_name') # 获取提交的数据,getlist以列表形式 author_obj = models.Author.objects.create(name=author_name) # 只插入book表中的内容 author_obj.books.set(book_name) # 设置作者和书籍多对多的关系
-
修改
books = request.POST.getlist('books') # 修改对象的数据 author_obj.name = name author_obj.save() # 多对多的关系 author_obj.books.set(books) # 每次重新设置
批量插入
bulk_create():批量插入数据,减少SQL查询次数,没插入一条数据就要查询一次
querysetlist=[]
for i in resultlist:
# models.Account(name=i),
querysetlist.append(models.Account(name=i))
models.Account.objects.bulk_create(querysetlist,batch_size=10)
# querysetlist:对象列表
# batch_size=10:单次插入数据量,一次插入10条,如果一共五十条数据,就插入五次
ORM中的常用方法
返回queryset对象列表的方法
-
all():获取所有数据,返回一个queryset对象列表
-
filter():获取指定内容的所有数据,返回一个queryset对象列表
-
exclude():获取不满足条件的所有数据
ret = models.Person.objects.exclude(pk=1) # 获取除了pk=1以外的所有数据
-
values():
# values():获取对象所有的字段和字段的值,一个字典对应一行数据 ret = models.Person.objects.values() # Queryset [{'字段':'值'},{'字段':'值'}...] # values('name','pid'):获取对应字段和值 ret = models.Person.objects.values('name','pid') # Queryset [{'name':'值','pid':'值'}...] # values(flat=True): 添加该参数可直接获取对象的id
-
values_list():
# values_list():拿到对象所有字段的值,以元组形式存于列表中 ret = models.Person.objects.values_list() # QuerySet [ () ,() ] # values_list('name','pid'):拿到对象指定字段的值,以元组形式存于列表中 ret = models.Person.objects.values_list('name','pid')
-
order_by():排序
# 默认是升序,如果按降序排列在字段前加-,如:-pid ret = models.Person.objects.all().order_by('age','-pid') # 先以age按照升序排列后,再按照pid按照降序排列
-
reverse():反转,反向排序
# 注:必须是已经排序好的Queryset列表,才能使用反转 ret = model.Person.objects.all().order_by('name') r = ret.reverse()
-
distinct():去重
# 完全相同的内容才能去重 ret = models.Person.objects.values('age').distinct()
orm操作返回对象的方法
-
get():获取满足条件的一个数据
-
first():获取第一个元素,没有返回None
ret = models.Person.objects.filter(pk=1).values().first()
-
last():取最后一个元素,没有返回None
ret = models.Person.objects.filter(pk=1).first()
orm操作返回数字的方法
-
count():计数
ret = models.Person.objects.all().count() # 计算列表中有多少个对象
orm操作返回布尔值的方法
-
exists():查询数据是否存在
ret = models.Person.objects.filter(pk=1000).exists()
单表的双下划线
-
__gt
:大于 greater thanret = models.Person.objects.filter(pk__gt=1) # 取pk>1的数据
-
__gte
:大于等于 greater than equalret = models.Person.objects.filter(pk__gte=1) # 取pk>=1的数据
-
__lt
:小于 less thanret = models.Person.objects.filter(pk__lt=1) # 取pk<1的数据
-
__lte
:小于等于 less than equalret = models.Person.objects.filter(pk__lte=1) # 取pk<=1的数据
-
__range
:取范围数据ret = models.Person.objects.filter(pk__range=[1,4]) # 取pk在1-4之间的数据,包含1,4
-
__in
:取成员ret = models.Person.objects.filter(pk__in=[1,2,4]) # 取pk在[1,2,4]中的数据
-
__contains
:包含,相当于mysql中的模糊查询ret = models.Person.objects.filter(name__contains='A') # 取name包含A的数据 ret = models.Person.objects.filter(name__icontains='A') # 忽略大小写
-
__startswith
:以...开头ret = models.Person.objects.filter(name__startswith='A') # 取name以A开头的数据 ret = models.Person.objects.filter(name__istartswith='A') # 忽略大小写
-
__endswith
:以...结尾ret = models.Person.objects.filter(name__endswith='A') # 取name以A结尾的数据 ret = models.Person.objects.filter(name__iendswith='A') # 忽略大小写
-
__year
:筛选年份ret = models.Person.objects.filter(birth__year='2019') # 取birth年份是2019的数据
-
__isnull
:判断是否为空ret = models.Person.objects.filter(phone__isnull=False) # 取phone不为null的数据 ""空字符串不为null。
外键的操作
-
外键表示了表与表之间的关系
-
建表语句,以下操作均是基于此表
from django.db import models class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name="名称") def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=32) pub = models.ForeignKey( Publisher, related_name='books',related_query_name='xxx',on_delete=models.CASCADE ) def __str__(self): # 指定__str__,方便查看区分对象 return self.title
-
基于对象的
# 正向查询 book_obj = models.Book.objects.get(title='菊花怪大战MJJ') book_obj.pub # 获取到title这本书的queryset关系管理对象 book_obj.pub.all() # 获取对应的出版社信息queryset对象 # 反向查询 pub_obj = models.Publisher.objects.get(pk=1) pub_obj.book_set # 获取到出版社id=1的对应书的queryset关系管理对象 pub_obj.book_set.all() # 获取出版社信息对应的书queryset对象 # book_set 类名小写_set 没有指定related_name时使用 # 如果指定related_name,则不使用“类名小写_set”,直接使用related_name的值
-
基于字段的
# 查询老男孩出版社的书 ret = models.Book.objects.filter(pub__name='老男孩出版社') # __表示跨表,从pub所在表跨到name所在表 print(ret) # 得到book表 Queryset对象列表 # 查询出版菊花怪大战MJJ的出版社 ret= models.Publisher.objects.filter(books__title='菊花怪大战MJJ') #设置related_name的值 ret= models.Publisher.objects.filter(book__title='菊花怪大战MJJ') # 未设置related_name的值,用类名小写 ret= models.Publisher.objects.filter(xxx__title='菊花怪大战MJJ') # 如果设置了related_query_name='xxx',就要用他的值xxx
-
关系管理对象:外键中不能使用id只能使用对象
# set方法 pub_obj.books.set(models.Book.objects.filter(pk__in=[4,5])) # 不能用id 只能用对象 # add方法 pub_obj.books.add(*models.Book.objects.filter(pk__in=[1,2])) # create方法 pub_obj.books.create(title='python') # 外键可为空时才有remove clear pub_obj.books.remove(*models.Book.objects.filter(pk__in=[1,2])) pub_obj.books.clear()
一对多关系管理对象的方法
-
关系管理对象
pub_obj = models.Publisher.objects.get(pk=1) # pk=1对应的出版社对象 pub_obj.books # 关系管理对象
-
set():设置一对多关系
# 只能为对象 pub_obj.books.set(models.Book.objects.filter(pk__in=[1,2,4,5]))
-
add():添加一对多关系
# 只能为对象 pub_obj.books.add(*models.Book.objects.filter(pk__in=[4,5])) # 添加对象时,由于filter获取的是对象关系列表,所以要获取其中每个对象,通过*解包
-
remove():删除一对多关系,只有当外键设置null=True时才行
# 只能为对象 pub_obj.books.remove(*models.Book.objects.filter(pk__in=[4,5]))
-
clear():清空所有多对多关系,只有当外键设置null=True时才行
pub_obj.books.clear() # 清空所有obj对应书籍的一对多关系
多对多
-
建表代码
class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name="名称") def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=6, decimal_places=2) # 9999.99 sale = models.IntegerField() kucun = models.IntegerField() pub = models.ForeignKey(Publisher, null=True,on_delete=models.CASCADE) def __str__(self): return self.title class Author(models.Model): name = models.CharField(max_length=32, ) books = models.ManyToManyField(Book) def __str__(self): return self.name
-
基于对象的
"""正向查询""" obj = models.Author.objects.get(pk=1) obj.books # 关系管理对象 obj.books.all() # 获取book的queryset对象列表 """反向查询""" book_obj = models.Book.objects.filter(title='桃花怪大战菊花怪').first() # 不指定related_name book_obj.author_set # 关系管理对象 book_obj.author_set.all() # 获取author的queryset对象列表 # related_name='authors' book_obj.authors # 关系管理对象 book_obj.authors.all()
-
基于字段的
obj = models.Author.objects.filter(books__title='菊花怪大战Mjj') # 这里的__表示跨表 # 查询'菊花怪大战Mjj'这本书对应作者的对象列表,从books跨到title所在这个表 obj = models.Book.objects.filter(author__name='Mjj') # 不指定related_name # 查询作者'Mjj'对应的书的对象列表 obj = models.Book.objects.filter(authors__name='Mjj') # related_name='authors' obj = models.Book.objects.filter(xxx__name='Mjj') # related_query_name='xxx'
多对多关系管理对象的方法
author_obj = models.Author.objects.get(pk=1) # pk=1对应的作者对象
author_obj.books # 关系管理对象
set():设置多对多关系
# 参数可以是id,也可以是对象
author_obj.books.set([1,2,3]) # 将查询出的obj对应作者与pk为[1,2,3]的书设置多对多关系
# 内部是先将原来的删除,然后把新的内容添加进去
author_obj.books.set(models.Book.objects.filter(pk__in=[1,2,4,5]))
add():添加多对多关系
author_obj.books.add(4,5) # 给obj对应的作者添加pk为4和5的多对多关系
内部已经有的不会再新增
author_obj.books.add(*models.Book.objects.filter(pk__in=[4,5]))
# 添加对象时,由于filter获取的是对象关系列表,所以要获取其中每个对象,通过*解包
remove():删除多对多关系
author_obj.books.remove(4,5) # 给obj对应的作者删除pk为4和5的多对多关系
author_obj.books.remove(*models.Book.objects.filter(pk__in=[4,5]))
clear():清空所有多对多关系
author_obj.books.clear() # 清空所有obj对应作者的多对多关系
create():创建一个所关联的对象,并且和当前对象添加多对多关系
author_obj.books.create(title='天龙八部',pub_id=1)
# 通过作者对象创建书的内容,书中有title和pub外键
book_obj = models.Book.object.filter(pk=2).first() # 通过书籍对象创建作者的内容
book_obj.author_set.create(name='xiaoqi')
update():批量更新数据
models.Customer.objects.filter(pk__in=pk).update(consultant=self.request.user_obj)
# 筛选出pk字段在pk中的数据,所有数据更新consultant字段值为self.request.user_obj
分组聚合
建表代码
class Publisher(models.Model):
name = models.CharField(max_length=32, verbose_name="名称")
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6, decimal_places=2) # 9999.99
sale = models.IntegerField()
kucun = models.IntegerField()
pub = models.ForeignKey(Publisher, null=True,on_delete=models.CASCADE)
def __str__(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=32, )
books = models.ManyToManyField(Book)
def __str__(self):
return self.name
聚合
from django.db.models import Max,Min,Sum,Avg,Count # 先导入聚合函数
ret = models.Book.objects.filter(pk__gt=3).aggregate(Max('price'),avg=Avg('price'))
# avg=Avg('price')等于是给平均函数重新命名,关键字参数
# 获取pk大于3的最大值,和平均值
# aggregate返回的是一个字典,可以.keys()等字典操作,后面不能在查其他的,比如.filter
# aggregate聚合
分组
annotate 注释的意思,将聚合的结果作为一个注释放到原来的对象里,
官方解释:每个参数annotate()都是一个注释,将被添加到QuerySet返回的每个对象中。
# 统计每一本书的作者个数
ret = models.Book.objects.annotate(count = Count('author')).values()
for i in ret:
print(i)
{'id': 1, 'title': '跟金老板学开车', 'publish_date': datetime.date(2018, 8, 3), 'price': Decimal('12.90'), 'memo': None, 'publisher_id': 1, 'count': 2}
可以看出将查询的内容添加至queryset并返回到每个对象中。
# 统计出每个出版社的最便宜的书的价格
方式一:
ret = models.Publisher.objects.annotate(Min('book__price')).values()
方式二:
ret = models.Book.objects.values('pub_id').annotate(Min('price')).values()
# objects后面.values表示分组的条件,参数是按照谁分组
# 统计不只一个作者的图书
ret = models.Book.objects.annotate(count = Count('author__name')).filter(count__gt=1)
# 查询每个作者出的书的总价格
ret = models.Author.objects.annotate(Sum('books_price')).values()
F查询 & Q查询
F:两个字段之间对比,或操作数据表的某列
from django.db.models import F
models.Book.objects.filter(sale__gt=F('kucun')) # 找到销量大于kucun的书籍,两个字段之间的比较
update:批量更新
models.Book.objects.all().update(sale=F('sale')*2+10) # 取某个字段的值进行操作
Q(条件):对对象进行复杂查询,并支持与&,或|,非~操作符
from django.db.models import Q
ret = models.Book.objects.filter(~Q(Q(pk__gt=3) | Q(pk__lt=2)) & Q(price__gt=50))
# 与&,或|,非~
q = Q()
q.connector = 'OR' # 表示Q中的元素之间的关系是或的关系,默认是与的关系。
q.children # 表示Q()中的元素,是一个列表。
q.children.append(Q(pk=1))
q.children.append(Q(pk=2)) # Q(pk=1),Q(pk=2)这两个元素都在q = Q()中
Q(('pk',1))-->等价于Q(pk=1) # 可查看源码