ORM多表操作

编辑本博客

yuan先生博客

一、ORM多表创建

一对多:关联字段必须创建在多的一方

多对多:创建第三张关联表

一对一:即一张大表拆分成多个小表,关系字段创建在任何一张表均可,需在关联字段上创建unique约束

from django.db import models
from django.db.models import CharField,EmailField,AutoField,DateField,IntegerField,BigIntegerField,DecimalField,ForeignKey,OneToOneField,ManyToManyField
# Create your models here.
class AuthorDetail(models.Model):
    nid=AutoField(primary_key=True)
    birthday=DateField()
    telephone=BigIntegerField()
    addr=CharField(max_length=128)
class Author(models.Model):
    nid=AutoField(primary_key=True)
    name=CharField(max_length=64)
    age=IntegerField()
    #一对一,相对于ForeignKey多一个unique约束
    authordetial=OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)
class Publish(models.Model):
    nid=AutoField(primary_key=True)
    name=CharField(max_length=64)
    city=CharField(max_length=64)
    email=EmailField()

class Book(models.Model):
    nid=AutoField(primary_key=True)
    title=CharField(max_length=64)
    publishDate=DateField()
    price=DecimalField(max_digits=5,decimal_places=2)
    #一对多
    publish=ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    #多对多,生成第三张表,不会在book表上添加新字段
    authors=ManyToManyField(to="Author")
View Code

setting中设置数据库引擎为MySQL

DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.mysql',
        'NAME':'orm2',
        'USER':'root',
        'PASSWORD':'123.com',
        'HOST':'127.0.0.1',
        'PORT':3306
    }
}
View Code

注意:

  • 表名用为app_table
  • 会自动添加ID字段,
  • 对于外键字段,Django会自动添加上_id
  • 在setting文件中注册app名称,否则迁移的时候不会成功
  • 外键ForeignKey有个null=True的参数,他允许外键接受NULL,可以给赋空值None

多表数据添加

一对多:

方式一:

给publish_id赋值

def add(request):
    new_publish=Publish.objects.create(name="人民出版社",city="BeiJing",email="[email protected]")
    new_book=Book.objects.create(title="西游记",price=100,publishDate="1890-12-1",publish_id=new_publish.nid)
View Code

方式二:

扫描二维码关注公众号,回复: 1908611 查看本文章

给publish赋值,非publish_id,不能直接赋一个ID值,需要赋值一个实例对象,实例对象通过QuerySet的first()或[0]的方式取得

publish=Publish.objects.filter(nid=7).first()
    new_book = Book.objects.create(title="水浒传", price=166, publishDate="1890-12-1", publish=publish)
View Code

 无论哪种方式赋值添加,查询取得的publish都是是一个Publish对象,可以通过“.”获取相关属性

多对多:

通过“关联”字段对象add方法添加

方式一:

直接传入对象

方式二:

传入对象主键id

方式三:

传入对象主键id列表

#绑定多对多关系
    new_book=Book.objects.create(title="红楼梦",price=200,publishDate="1990-1-1",publish_id=7)
    yaya=Author.objects.filter(name='yaya').first()
    huangya=Author.objects.filter(name="huangya").first()
    #给第三张关联表添加数据,即绑定对多对关系的API
    #方式一
    new_book.authors.add(huangya,yaya)
    #方式二,传入主键
    new_book.authors.add(1, 4)
    #方式三,传入主键列表
    new_book.authors.add(*[1, 4])
View Code

解除关联关系

方式一:

obj.authors.remove(1,4)

方式一:

obj.authors.remove(*[1,4])

方式一:

obj.authors.remove(huangya,yaya)

方式四:

obj.authors.clear()清除所有多对多关系

new_book=Book.objects.get(nid=3)
new_book.authors.remove(1)
new_book.authors.remove(huangya)
View Code

注:

  • 创建外键的时候,一定要注意实际Django在关联字段后面添加了_id
  • 关联字段和被关联字段同时创建和关联时,如果关联失败,那么被关联表的数据不影响插入

二、多表数据查询

查询方向:关联属性在A表,那么通过A对象查询B,则为正向查询。通过B查询A则为反向查询

(一)、基于对象的跨表查询

相当于mysql的子查询

一对多:

正向查询:通过字段查询

#正向查询按字段
book_obj=Book.objects.filter(title='西游记').first()
print(book_obj.publish.name)
View Code

反向查询:通过表名小写查询,固定语法,表名小写_set

    #反向查询按表名
    publish_obj=Publish.objects.filter(name='人民出版社').first()
    #返回一个QuerySet
    books=publish_obj.book_set.all()
    print(books)
View Code

多对多:

正向查询按字段查询,反向查询按表名小写查询。和一对多一样

正向查询:

    #查询书籍的作者名称
    book_obj=Book.objects.filter(title="红楼梦").first()
    #该书籍的所有作者集合,QuerySet对象
    author_list=book_obj.authors.all()
    for author in author_list:
        print(author.name)
View Code

反向查询:

    #反向查询
    author_obj=Author.objects.filter(name='yaya').first()
    books=author_obj.book_set.all()
    for book in books:
        print(book.title)
View Code

 一对一:

正向查询按字段,反向查询按表名小写,无_set,即非集合

正向查询:

    author_obj=Author.objects.filter(name="huangya").first()
    #正向插叙
    print(author_obj.authordetial.telephone)
View Code

反向查询:

    #反向查询
    detial_obj=AuthorDetail.objects.filter(telephone='17589742390').first()
    print(detial_obj.author.name)
View Code

(二)、基于双下划线的跨表查询

相当于mysql的join查询

正向查询按字段下旬,反向查询按表名小写查询。告知ORM引擎join那张表

一对多:

方式一,正向查询values

无过滤条件

#SELECT app_publish.name,app_publish.city FROM app_book INNER JOIN app_publish
res5=Book.objects.values('publish__name','publish__city')
View Code

添加过滤条件

#SELECT app_publish.name,app_publish.city FROM app_book INNER JOIN app_publish WHERE app_book.title="西游记"
res=Book.objects.filter(title="西游记").values('publish__name','publish__city')
View Code

 方式二,反向查询filter

#SELECT app_publish.name,app_publish.city FROM app_publish INNER JOIN app_book ON app_publish.nid = app_book.publish_id WHERE app_book.title="西游记"
Publish.objects.filter(book__title="西游记").values('name')
View Code

 

 多对多:

 查询《红楼梦》的作者

方式一、正向查询。通过book表join与其关联的author表

    SQL:
    SELECT app_author.name from app_book
    INNER JOIN app_book_authors ON app_book.nid =app_book_authors.book_id
    INNER JOIN app_author ON app_book_authors.author_id = app_author.nid
    WHERE app_book.title="红楼梦"
    """
    # ORM
    res=Book.objects.filter(title="红楼梦").values('authors__name')
View Code

方式二、反向查询。通过author表join与其关联的book表

Author.objects.filter(book__title="红楼梦").values('name')
View Code

一对一:

查询作者的电话号码

方式一:正向查询

Author.objects.filter(name="huangya").values('authordetial__telephone')
View Code

  方式二:反向查询

AuthorDetail.objects.filter(author__name="huangya").values('telephone')
View Code

 进阶查询

无关联,所以必须跨表查询

需求:查询手机号175开头的作者出版过的所有书籍名称以及书籍出版社名称。

方式一:

  Book.objects.filter(authors__authordetial__telephone__startswith="175").values('title','publish__name')
View Code

方式二:

Author.objects.filter(authordetial__telephone__startswith='175').values("book__title","book__publish__name")
View Code

(三)、聚合查询

导入Django函数,from django.db.models import Avg,Max,Min,Count

查询所有书籍平均价格

SQL语句:

SELECT avg(price) as avg from app_book;
View Code

ORM:

Book.objects.all().aggregate(Avg('price'))
View Code

返回字典,并非QuerySet

自定义键

Book.objects.all().aggregate(priceAvg=Avg('price'))
View Code

查询最大值与最小值。也可以像Avg()一样自定义键

Book.objects.all().aggregate(Max('price'),Min('price'))
View Code

(四)、分组查询

(五)、F与Q查询

猜你喜欢

转载自www.cnblogs.com/yaya625202/p/9272731.html