table of Contents
Django ORM multi-table CRUD
Create a relationship field
ORM create multi-table relationships through the use of field. Commonly used multi-table relationships are:
- ForeignKey foreign key, field-many relationship
- OneToOneField one relationship field
- ManyToManyField-many relationship field
Direct look at models.py
the code:
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
# 一对一
ad=models.OneToOneField(to="AuthorDetail", to_field="id", on_delete=models.CASCADE)
# to_field="id" 可以不写,默认找主键
# to="AuthorDetail", to=可以不用写
# on_delete=models.CASCADE 默认是级联删除,想做级联更新,直接去数据库修改表结构
# on_delete=models.SET_NULL 也可以设置成删除置空
class AuthorDetail(models.Model):
birthday=models.DateField()
telephone=models.CharField(max_length=16)
addr=models.CharField(max_length=64)
class Publish(models.Model):
name=models.CharField(max_length=32)
city=models.CharField(max_length=32)
class Book(models.Model):
title = models.CharField(max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5, decimal_places=2)
# 外键和多对多
publishs=models.ForeignKey(to="Publish", to_field="id", on_delete=models.CASCADE)
authors=models.ManyToManyField(to='Author')
The basic construction of the table statement is consistent with the single-table operation. There are many tables relationship one to one, one to many and many to many, respectively, can be created in the following three ways:
# 一对一,外键 + 唯一
ad=models.OneToOneField(to="AuthorDetail", to_field="id", on_delete=models.CASCADE)
# 一对多,外键
publishs=models.ForeignKey(to="Publish", to_field="id", on_delete=models.CASCADE)
# 多对多,创建第三张表
authors=models.ManyToManyField(to='Author')
When operating one or one to many association table, we can operate through the class attribute table or form fields, field name is usually 类属性名 + 下划线 + 外键名
:
- Class
ad
properties: ,publishs
- Field:
ad_id
,publishs_id
For many-direct operation of the third generation new tables, table name 应用名 + 下划线 + 当前表名 + 下划线 + 属性名
, may be operated by a third class attribute table fields and tables:
- Class properties:
authors
- Table Name:
app01_book_authors
id
Field:author_id
, ,book_id
It will be discussed in detail below their specific usage.
Multi-table CRUD
increase
One to One
As described above, one field may be added to increase the data associated with another table or through the use of the class attribute table fields:
models.AuthorDetail.objects.create(
birthday='2018-11-11',
telephone='15122220000',
addr='北京',
)
models.Author.objects.create(
name='金龙',
age=2,
ad=models.AuthorDetail.objects.get(id=1), # 类属性
)
models.Author.objects.create(
name='金龙2',
age=2,
ad_id=2, # 表字段
)
Many
Increase, with one-to-many is the same reason, you can add or through the class attribute table field:
models.Book.objects.create(
title='白洁',
publishDate='2011-01-01',
price=200,
publishs=models.Publish.objects.get(id=1) # 类属性
)
models.Book.objects.create(
title='白洁第二部',
publishDate='2011-01-01',
price=300,
publishs_id=1 # 表字段
)
Many to many
A book can have multiple authors, an author may write many books. For example, No. 1 of the book is written by two authors numbered 1 and 2, then the relationship between the author and the book's table, we should create a relationship between the two books 1 2 1 author and book author 1, it like this:
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
+----+---------+-----------+
The specific operation in two ways, one is added through the object, and the other is a value added directly
Add an object by object
By finding the object of an object, use the Add method to add:
book_obj = models.Book.objects.get(id=1)
author1 = models.Author.objects.get(id=1)
author2 = models.Author.objects.get(id=2)
book_obj.authors.add(author1, author2)
# book_obj.authors.add(*[author1, author2])
By adding primary key id
By author id, adding author information directly book:
book_obj = models.Book.objects.get(id=1)
book_obj.authors.add(1, 2)
# book_obj.authors.add(*[1, 2])
delete
One to one and one to many
After one to one and one to many to find the object is deleted objects, direct delete Delete:
models.Author.objects.get(id=1).delete()
Many to many
Many-to-delete operation requires the use of query objects:
book_obj = models.Book.objects.get(id=1) # 找到id为1的书
book_obj.authors.remove(3) #删除id为1的书与id为3的作者之间的关系
book_obj.authors.remove(2, 3) # 删除id为1的书与id为2和3的作者之间的关系
book_obj.authors.clear() # 清空id为1的书的所有作者信息
modify
One to one and one to many
Modify the update, and one-to-many operation and single-table is the same:
models.Book.objects.filter(id=1).update(
title='白洁新版',
# publishs=models.Publish.objects.get(id=3),
publishs_id=3
)
Many to many
book_obj.authors.set(['4',]) # 先清空再添加 clear+add
Inquire
Based on cross-table query object
One to One
Forward inquiry
2 Golden Dragon query the author's home address
author_obj = models.Author.objects.get(name='金龙2')
# author_obj.ad -- 直接拿到authordetail表中的那个条记录对象
print(author_obj.ad.addr)
Reverse Lookup
Inquiries number to 151 at the beginning of the author's name
authordetail_obj = models.AuthorDetail.objects.filter(telephone__startswith='151').first()
print(authordetail_obj.author.name)
Many
Forward inquiry
Bai Jie new version of the book which is published by the
book_obj = models.Book.objects.filter(title='白洁新版').first()
print(book_obj.publishs.name)
Reverse Lookup
Tokyo publishing house published a book which
pub_obj = models.Publish.objects.get(name='东京出版社')
books = pub_obj.book_set.all().values('title')
# 东京出版社出版的名称中还有白洁的那些书
books = pub_obj.book_set.filter(title__contains='白洁').values('title')
print(books)
Many to many
Forward inquiry
Bai Jie new version of the author of this book who have
book_obj = models.Book.objects.filter(title='白洁新版').first()
authors = book_obj.authors.all().values('name')
print(authors)
Reverse Lookup
Inquiries about what book to write Jinlong 2
jinlong2_obj = models.Author.objects.get(name='金龙2')
ret = jinlong2_obj.book_set.all().values('title')
print(ret)
Cross-table query summary
- Forward Query by property
- If you are one, reverse lookup by class name in lowercase
- And many-to-many, reverse lookup by class name in lowercase _set
Based on cross-table double-underlined query (join)
One to One
Forward-linked table on property
Query Xudong home address
ret = models.Author.objects.filter(name='旭东').values('ad__addr')
print(ret)
If expressed in SQL statements, it should look like this:
select app01_authordetail.addr from app01_author inner join app01_authordetail on app01_author.ad_id = app01_authordetail.id where app01_author.name='旭东';
Even reverse the table class name in lowercase
ret = models.AuthorDetail.objects.filter(author__name='旭东').values('addr')
print(ret)
Many
Discover what books published by Tokyo.
If the direct use of SQL statements should be written:
select app01_book.title from app01_publish inner join app01_book on app01_publish.id = app01_book.publishs_id where app01_publish.name='东京出版社';
The use of ORM, is written like this:
ret = models.Publish.objects.filter(name='东京出版社').values('book__title')
print(ret)
ret = models.Book.objects.filter(publishs__name='东京出版社').values('title')
print(ret)
Many to many
Inquiries about what book to write Jinlong 2
ret = models.Book.objects.filter(authors__name='金龙2').values('title')
print(ret)
ret = models.Author.objects.filter(name='金龙2').values('book__title')
print(ret)
Aggregate query
aggregate aggregate queries, the result is ordinary dictionary, QuerySet terminator.
from django.db.models import Avg,Max,Min,Count,Sum
obj = models.Book.objects.all().aggregate(a=Max('price')) #{'price__avg': 200.0}
print(obj)
Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
Grouping queries
Grouping queries written in SQL statement should be:
group by app01_book.publishs_id
For example: find the highest price of each book published by
After the first group values
ret = models.Book.objects.values('publishs_id').annotate(m=Max('price'))
print(ret)
Summary: values written on the front annotate, meaning based on field values in parentheses as the basis for grouping. annotate there is statistical results you have to do. Thus, the result is returned queryset type data, which is a dictionary:
{'publishs_id':1,'m':100}
After the first group values
ret = models.Publish.objects.annotate(m=Max('book__price')).values('m', 'name')
print(ret)
Summary: annotate directly written on the back of objects, meaning that all of the data in accordance with the previous table (the default is id value) of the grouping. Return result is that all models objects in front of the table (each object contains its statistical model object), and then to the value by values. Fields can write and direct statistical results when the value of an alias, also queryset type, which is the dictionary:
{'m': 100, 'name': '东京出版社'}
Queries highest price for each author's name and the publication of the book:
ret = models.Book.objects.values('authors__name', 'authors__id').annotate(m=Max('price')) # group by authors__name,authors__id
print(ret)
ret = models.Author.objects.annotate(m=Max('book__price')).values('name', 'm')
print(ret)
Query F
Import ways:
from django.db.models import F
The results are in Table F query result set qualified after comparison of two fields.
Like point is greater than the number of inquiries about all the books the number of comments.
In the past, we can also be found by using a loop:
list1 = []
books = models.Book.objects.all()
for i in books:
if i.dianzan > i.comment:
list1.append(i)
If you are using F query, the code will be more simple and intuitive:
ret = models.Book.objects.filter(dianzan__gt=F('comment')).values('title')
ret = models.Book.objects.filter(dianzan__lt=F('comment')).values('title')
print(ret)
Field This four operations:
models.Book.objects.all().update(
price=F('price') + 20 # 支持四则运算
)
Q query
Import ways:
from django.db.models import Q
Performs a logical operation for the query Q, Q of the connector:
& -- and
| -- or
~ -- not,取反
Like inquiries about point greater than 300 or less than the price of the book 300
ret = models.Book.objects.filter(Q(dianzan__gt=300)|~Q(price__lt=500),xx='oo').values('title')
ret = models.Book.objects.filter(Q(dianzan__gt=300)).values('title')
ret = models.Book.objects.filter(Q(Q(dianzan__gt=300)|~Q(price__lt=500))&Q(xx='oo')).values('title') # Q查询能够进行各种复杂条件的拼接
print(ret)
Multi-table queries practice example:
# 1 查询每个作者的姓名以及出版的书的最高价格
ret = models.Author.objects.values('id','name').annotate(m=Max('book__price'))
print(ret)
# 2 查询作者id大于2作者的姓名以及出版的书的最高价格
ret = models.Author.objects.filter(id__gt=2).values('name').annotate(a=Max('book__price'))
print(ret)
# 3 查询作者id大于2或者作者年龄大于等于3岁的女作者的姓名以及出版的书的最高价格
ret = models.Author.objects.filter(Q(id__gt=2)|Q(Q(age__gte=3)&Q(sex='女'))).values('name').annotate(a=Max('book__price'))
print(ret)
# 4 查询每个作者出版的书的最高价格 的平均值
ret = models.Book.objects.values('authors__name').annotate(m=Max('price')).aggregate(a=Avg('m'))
print(ret)
# 5 每个作者出版的所有书的最高价格以及最高价格的那本书的名称
ret = models.Book.objects.values('authors__name').annotate(m=Max('price'))
queryset({'authors__name':'xx','m':100},{'authors__name':'xx','m':100},)