5.Django|模型层--多表关系

多表操作

一对多Book
    id    title    price    publish         email    addr
    1    php        100        人民出版社     111    北京
    2    python     120        沙河出版社     222    沙河
    3    go         110        人民出版社     119    北京
    4    java       300        人民出版社     111    北京

Book多
    id    title    price    publish_id
    1    php        100            1
    2    python     120            1
    3    go         110            2
    4    java       300            1    

Publish一
    id    name         email    addr
    1    人民出版社     111      北京
    2    沙河出版社     222      沙河

查询python这本书的出版社的邮箱(子查询)
    select publish_id from Book where title="python"
    select email  from Publish where id=1  id=(上边的)

    一旦确定是一对多的关系:建立一对多的关系------->在多的表中建立关联字段

多对多:
Book
    id    title    price    publish_id
    1    php        100            1
    2    python     120            1
    3    go         110            2
    4    java       300            1    

Author
    id    name    age        addr
    1    alex    34         北京
    2    egon    55         南京

Book2Author
    id    book_id        author_id
    1      2            1
    2      2            2
    3      3            2

alex出版过的书籍名称(子查询)
select id form Author where name=‘alex‘  (拿到alex这个id)
select book_id from Book2Author where author_id=1
select title from Book id=book_id    

一对一:
Author
    id    name    age        Authordetail_id(unique)
    1    alex    34            1
    2    egon    55            2

AuthorDetail
    id    addr    gender        tel        gf_name
    1    北京    male        110        小花
    2    南京    male        911        小红

一旦确定是一对多的关系:建立一对多的关系------->在多的表中建立关联字段    (一个出版社可以出版多本书)
一旦确定多对多的关系:建立多对多的关系--------->创建第三张表(关联表):id和两个关联字段   (一本书可以有多个作者,一个作者可以出版多本书;)
一旦确定一对一的关系:建立一对一的关系---------->在两张表中的任意一张表中建立关联字段+unique  (一个作者只有一个详细信息)

对应的sql语句

PublishBookAuthorAuthorDetailBook2Author

CREATE TABLE publish(
        id INT PRIMARY KEY auto_increment,
        name VARCHAR(20)
        );
CREATE TABLE book(
        id INT PRIMARY KEY auto_increment,
        title VARCHAR (20),
        price DECIMAL (8,2),
        pub_date DATE,
        publish_id INT,
        FOREIGN KEY (publish_id) REFERENCES publish(id)  一个出版社可以出版多本书
        );
CREATE TABLE authordetail(
        id INT PRIMARY KEY auto_increment,
        tel VARCHAR(20)
        );
CREATE TABLE author(
        id INT PRIMARY KEY auto_increment,
        name VARCHAR(20),
        age INT,
        authordetail_id INT UNIQUE,
        FOREIGN KEY(authordetail_id) REFERENCES authordetail(id)  一个作者只有一个详细信息
        );
    CREATE TABLE book2author(
        id INT PRIMARY KEY auto_increment,
        book_id INT,
        author_id INT,
        FOREIGN KEY(book_id) REFERENCES book(id),
        FOREIGN KEY(author_id) REFERENCES author(id)            一个书可以有多个作者,一个作者可以出版多本书
        );

创建模型

models

from django.db import models

# Create your models here.

‘‘‘
Book ----> Publish 一对多
‘‘‘
#作者详情表
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)

class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()
    # 与AuthorDetail建立一对一的关系
    authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)  to_field="nid"这个可加可不加,它会默认去关联主键

#出版社表
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)   id字段是自动添加的,如果不加主键数据库迁移的时候它也会给你默认生成一个id的字段,可以不写nid,写了就用你写的。
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)
  #建立一对多关联要有一个关联字段,上边的都是普通字段;给关联字段再绑定约束关系;
    # 与Publish建立一对多的关系,外键字段建立在多的一方;django会自动给你补全publish_id;to就是foreign key哪个;加上引号就会在全局里边找;
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE, null=True) #关联主键nid;这句话相当于下面两句;在django2.0要加上on_delete=models.CASCADE;null=True是允许这个字段为空
    ‘‘‘
    publish_id INT,
    FOREIGN KEY(publish_id)REFERENCES publish(id)   to_field这个字段的nid主键;上边的publish在数据库迁移的时候就是这两句话
    ‘‘‘
    #多对多,会自动生成第三张表;下面的几个意思是一样的
    authors = models.ManyToManyField(to="Author")
    ‘‘‘
    CREATE TABLE book2author(      上边那一句话执行的结果就相当于会生成这个;book_authors它就是这样拼的
        id INT PRIMARY KEY auto_increment,
        book_id INT,
        author_id INT,
        FOREIGN KEY(book_id)REFERENCES book(id),
        FOREIGN KEY(author_id)REFERENCES author(id),
    )
    ‘‘‘
# class Book2Author(models.Model):  这是自己写的第三张表
#     nid = models.AutoField(primary_key=True)
#     book = models.ForeignKey(to="Book") to_field="nid"
#     author = models.ForeignKey(to="Author")
C:\Users\Administrator\PycharmProjects\orm2>python manage.py makemigrations
Migrations for ‘app01‘:
  app01\migrations\0001_initial.py
    - Create model Author
    - Create model AuthorDetail
    - Create model Book
    - Create model Publish
    - Add field publish to book
    - Add field authorDetail to author

C:\Users\Administrator\PycharmProjects\orm2>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, app01, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying app01.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

生成了5张表;book_authors生成的表;book表生成了一个publish_id字段;

注意事项:

  •  id 字段是自动添加的
  • 对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
  • 这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
  • 定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
  • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

一对一就是oneToOneField;一对多就是ForeignKey;它俩是一样的,会在那张表里边多生成一个字段,加一个_id+一个约束关系;多对多就是ManyToManyField,会生成一个第三张关系表;

多表操作

单表(没有任何关联字段)操作添加记录有两种一个是create,一个是obj.save(实例化来一个对象,用这个对象.sabe)

一对多添加记录(如果在有绑定关系的表中添加记录)

from django.shortcuts import render, HttpResponse

# Create your views here.
from app01.models import *
def add(request):
    pub = Publish.objects.create(name="人民出版社", email="[email protected]", city="北京")  Publish是单表,可以直接生成一个出版社记录
###################绑定一对多的关系##############
    #方式一:
    #为book表绑定关系 和出版社的关系:book多----->publish 1
    #book_obj = Book.objects.create(title="红楼梦", price=100, publishDate="2012-12-12", publish_id=1)
    #print(book_obj.title)  #返回值book_obj就是添加记录的对象

    #方式二:
    # pub_obj = Publish.objects.filter(nid=1).first() 查询id为1的出版社对象;不加first就是queryset的那个集合
    # book_obj = Book.objects.create(title="水浒传", price=100, publishDate="2012-12-12", publish=pub_obj) #publish就是book表里边的那个;让它等于publish的一个实例模型对象,赋值的时候pub_obj给了它一个对象;相当于它把上边第一种方式的翻译过来了
    # print(book_obj.title) 打印它的title
    # print(book_obj.price)
    # print(book_obj.publishDate)
    # print(book_obj.publish) #拿到的就是出版社对象;方式一的话是查到为1再赋给它  #它就是与这本书关联的出版社对象,一个书只有一个出版社对象;无论方式一还是方式二都可以.publish或者publish_id;它打印出来是Publish object(1);在那张表中加上__str__(self)就显示name了,打印出来那个出版社看起来是字符串其实是个对象,可以继续在对象之前取.
    # print(book_obj.publish_id)

    #查询西游记的出版社对应的邮箱;
    book_obj = Book.objects.filter(title="西游记").first()  #先把这个对象取出来;
    print(book_obj.publish.email) #先拿出一个对象找出它的关联对象,再去.  publish为什么可以.出来,是因在赋值的时候已给它对象了,方式一或二都可以
    return HttpResponse("ok")

多对多

通过第三张表给它绑定两个作者;你没办法直接给这张表添加记录,数据库知道这张表叫什么,orm不知道这张表叫什么名字;django给我们提供了一个接口。

###############绑定多对多的关系######################
    # book_obj = Book.objects.create(title="三国演义", price=100, publishDate="2012-12-12", publish_id=1)
    #
    # egon = Author.objects.get(name="egon") #把这两个作者找出来
    # alex = Author.objects.get(name="alex")
    # #绑定多对多的关系的API
    # book_obj.authors.add(egon, alex) #作者对象;book_obj为书籍对象,给它添加作者;它所要做的事情就是,book_obj的主键是1它马上要生成一个4,egon是2,alex是1;这句话它去找到book_obj和author之间的关联表,然后去表中生成记录,4 1、4 2生成两条记录
    # #book_obj.authors.add(1, 2, 3) #这是另外一种简洁的形式,用4跟1拼一个,4跟2拼一个,4跟3,这样的三条记录;直接放author的主键。作者主键值;
    # #book_obj.authors.add(*[1,2,3]) #跟上边的效果是等效的,*是在给函数传列表时等效位置参数加*

    #解出多对多关系
    book = Book.objects.filter(nid=4).first() #查到nid=4,把这本书拿到查出来了;
    # book.authors.remove(2) #加上1,2就把他们都删除了,删除4 1 、4 2;book的主键为4
    ##book.authors.remove(*[1,2]) #跟上边一样了

    #book.authors.clear()#全部删除

    #查询主键为4的书籍的所有作者的名字
    print(book.authors.all()) #拿出来的是一个集合,所有的,注意与上边.publish的区别[obj1、obj2....]queryset:与这本书关联的所有作者对象集合;列表里边套对象的格式;打印出<QuerySet [<Author: object(1)>]>;加上__str__就打印出了
    ret = book.authors.all().values("name")  <QuerySet [{‘name‘:‘alex‘}]>
print(ret) return HttpResponse("ok")
book_obj.publish      book.authors.all() 两个最核心的知识点;一对一,一对多的字段,意味着这张表的实例对象,当它.publish的时候它就会.出与它关联的出版社对象;当它.authors.all()的时候就会.出与它关联的作者集对象集合。

基于对象(子查询)之跨表查询

一对多

    ##############基于对象(就是先查出来拿到那个结果再去跨表去查到它相关的内容)的跨表查询######
    #####一对多
    ‘‘‘
    #一对多  正向按字段:publish
    book多    -------------->    publish 1
            <--------------
             反向按表名book_set.all() django封装的
    ‘‘‘
    #一对多的正向查询(确定关联字段放在哪里放在哪张表里,book表和publish表的关联字段在book表里边)
    #查询主键为1的书籍的出版社所在的城市
    # book_obj = Book.objects.filter(nid=1).first() 拿到book对象
    # print(book_obj.publish.city)

  ‘‘‘  select publish_id from Book where nid=1;  select city from publish where nid=1  ‘‘‘

    #反向查询
    #查询人民出版社出版社的所有书籍名称
    # publish_obj = Publish.objects.filter(name="人民出版社").first()
    # print(publish_obj.book_set.all()) #queryset列表里边放对象 [book1、book2...] <QuerySet [<Book: 红楼梦>, <Book: 西游记>, <Book: 水浒传>, <Book: 三国>]>
    #
    # for obj in publish_obj.book_set.all():
    #     print(obj.title)  #打印出了关联书籍的名字

一对一

    #####一对一(只是多了个unique)
    ‘‘‘
    #一对一  按字段(关联字段):authordetail
    author    -------------->    authordetail
            <--------------
             按表名author
    ‘‘‘
    ##############一对一
    #正向查询
    #查询alex的手机号
    # alex = Author.objects.filter(name="alex").first()  #拿到作者对象
    # print(alex.authordetail.telephone) #找出它的关联对象.authordetail
    #反向查询
    #查询手机号为911的的作者的名字
    ad = AuthorDetail.objects.filter(telephone=911).first() #AuthorDetail对象
    print(ad.author.name) #找它的关联对象,反向查询直接用表名author表

    return HttpResponse("ok")

多对多

    ##########多对多
    ‘‘‘
    #多对多  按字段authors
    book    ----------------------->    author
            <----------------------
             按表名book_set.all()
    ‘‘‘
    #正向查询
    #查询西游记所有作者的名字
    book = Book.objects.filter(title="西游记").first()
    print(book.authors.all()) #<QuerySet []>

    #反向查询
    #alex出版过的所有书籍名称
    alex = Author.objects.filter(name="alex").first()
    alex.book_set.all()
    for obj in alex.book_set.all():
        print(obj.title)

基于queryset双下划线的跨表查询(对应翻译的sql语句是join)

  Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

关键点:正向查询按字段,反向查询按表名。

    ########################基于双下划线的跨表查询:join查询########################################

    # 练习1:  查询苹果出版社出版过的所有书籍的名字与价格(一对多)   #以谁为基表以谁为左表都可以;

    ret=Publish.objects.filter(name="人民出版社").values("book__title","book__price")  #publish为左表,出版社去找书籍是反向查询;
    ret=Book.objects.filter(publish__name="人民出版社").values("title","price") #以book为左表,显示它的values它的字段
    print(ret)

    ‘‘‘依次对应上边的Book和Publish;这两种方式翻译成sql语句都一样
   SELECT * FROM "app01_book" INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."nid") WHERE "app01_publish"."name" = ‘人民出版社‘ LIMIT 21; args=(‘人民出版社‘,)

   SELECT * FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id") WHERE "app01_publish"."name" = ‘人民出版社‘ LIMIT 21; args=(‘人民出版社‘,)

    ‘‘‘
# 练习2: 查询alex出过的所有书籍的名字(多对多)
    ret = Author.objects.filter(name="alex").values("book__title") #跨表查询 正向
    ret = Book.objects.filter(authors__name="alex").values("title")  #  正向按字段,反向按表名

    # 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    ret = Book.objects.filter(publish__name="人民出版社").values("title", "authors__name") #只要不是这张表自己提供的就需要跨表

    # 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称  #用哪张表作为基表都可以的
    Book.objects.filter(authors__authordetail__telephone="151").values("title", "publish__title")  ##因为Book表只跟authors表有关联,所以最开始前边应加上这个;book表通过关系表跨到authors表

    return HttpResponse("ok")

聚合查询和分组查询

聚合aggregate(*args, **kwargs)
# 计算所有图书的平均价格
    from django.db.models import Avg
    ret = Book.objects.all().aggregate(price_avg=Avg("price"))   #{‘price__avg‘: 100.0}
    print(ret) #{‘c‘: 100.0}  {‘price_avg‘: 100.0}

    return HttpResponse("ok")
#分组查询

    from django.db.models import Avg,Count,Max
    #统计每本书的作者个数
    # ret = Book.objects.all().annotate(c=Count("authors__name"))  #它会把前边查出来的每一个对象进行分组统计,每一个对象就是一个组,统计每一个对象对应的作者的个数;涉及到关联的作者正向查询按字段反向按表名
    # print(ret)
    # for obj in ret:
    #     print(obj.title,obj.c)
        #<QuerySet [<Book: 红楼梦>, <Book: 西游记>, <Book: 水浒传>, <Book: 三国>]>
        # 红楼梦 0
        # 西游记 0
        # 水浒传 0
        # 三国 1

    #统计每一个作者出版过的书籍最高价格
    # ret=Author.objects.all().annotate(max_price=Max("book__price")) #通过Authors表去找它关联的书籍的价格,authors找书籍是反向查询 用表名
    # for obj in ret:
    #     print(obj.name, obj.max_price)
    #alex 600.00
    #egon 100.00

    #每一个出版社出版过的书籍的平均价格
    ret = Publish.objects.all().annotate(avg_price=Avg("book__price")).values("name", "avg_price") #publish关联的那个书籍,反向查询用表名;values每个出版社的名字、平均价格
    print(ret) #<QuerySet [{‘name‘: ‘人民出版社‘, ‘avg_price‘: 100.0}, {‘name‘: ‘人民出版社‘, ‘avg_price‘: 600.0}]>
    return HttpResponse("ok")

F查询和Q查询

http://www.cnblogs.com/yuanchenqi/articles/8963244.html

原文地址:https://www.cnblogs.com/shengyang17/p/9109973.html

时间: 2024-10-07 21:41:37

5.Django|模型层--多表关系的相关文章

Django模型层之单表操作

Django模型层之单表操作 一 .ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软件,例如mysql.oracle.Microsoft SQL Server等. 如果应用程序需要操作数据(比如将用户注册信息永久存放起来),那么我们需要在应用程序中编写原生sql语句,然后使用pymysql模块远程操作mysql数据库,详见图一^①^ 但是直接编写原生sql语句会存在两方面的问题,严

Django模型层之更多操作

Django模型层之更多操作 一 .ORM字段 1.1 常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. IntegerField 一个整数类型,范围在-2147483648 to 2147483647. CharField 字符类型,必须提供max_length参数, max_length表示字符长度. DateField 日期字段,日期格式 YYYY-MM-DD,相当于Python中的d

03 Django模型层: 常用(非常用)字段和参数

Django模型层: 常用(非常用)字段和参数 1 ORM字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. IntegerField 一个整数类型,范围在 -2147483648 to 2147483647. CharField 字符类型,必须提供max_length参数, max_length表示字符长度. DateField 日期字段,日期格式? YYYY-MM-DD,相当于Python中的

模型层单表操作

模型层单表操作 单表操作 例: 1. 单表的查询 1. 单表查询所有用户:models.Book.objects.all() 得到的是 queryset对象(当成列表),列表里面,一个一个的对象[user1,user2] ? 2. render(request, 'booklist.html', {'book_list': ret}) ? 3. 模板里: {% for user in book_list %} #要循环的内容 {{book.name}} {% endfor%} 4. get请求携

Django基础五之django模型层(一)单表操作

目录 一 ORM简介 二 单表操作 一.创建表 创建模型 2 更多字段和参数 3 settings配置 4.自定义字段(了解) 二.添加表纪录 方式1 方式2(用的多) 方式3:批量插入 三.查询表纪录 查询API(都是重点) 基于双下划线的模糊查询 四.删除表纪录 五.修改表纪录 三 章节作业 1 图书管理系统 2 查询操作练习 四 xxx 本节目录 一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,

Django基础五之django模型层(二)多表操作

目录 一 创建模型 关于db_column和verbose_name 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询(基于join实现的) 进阶练习(连续跨表) 五 聚合查询.分组查询.F查询和Q查询 查询练习 F查询与Q查询 F查询 Q查询 六 ORM执行原生sql语句(了解) 执行原生查询 直接执行自定义SQL 七 Python脚本中调用Django环境(django外部脚本使用models) 八 补充多个app配置models 本节目录 一 创建模型 表和表之间的关系

web框架开发-Django模型层(2)-多表操作

很重要,都是精华 多表关系模型 一对一 一旦确定表关系是一对一,在两张表中的任意一张表中建立关联字段+Unique 一对多 一旦确定表关系是一对多,创建关联字段在多的表中 多对多 一旦确定表关系是多对多,创建第三章关系表 ORM生成关系表模型 假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对一的关系(one-to-one) 出版商模型:出版商有名称,所在城市以及email. 书

Django之模型层-多表操作

多表操作 数据库表关系 一对多:两个表之间的关系一旦确定为一对多,必须在数据多的表中创建关联字段 多对多:两个表之间的关系一定确定为多对多,必须创建第三张表(关联表) 一对一:一旦两个表之间的关系确定为一对一,在两种表中任意一张表中建立关联字段unique ORM生成关联表模型 class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) pric

一 Django模型层简介

模型 django提供了一个强大的orm(关系映射模型)系统. 模型包含了你要在数据库中创建的字段信息及对数据表的一些操作 使用模型 定义好模型后,要告诉django使用这些模型,你要做的就是在配置文件中的INSTALLED_APPS中添加模型所在的应用名称 字段类型 模型中的每个字段都是Field类相应的实例,django根据Field类型来确定以下信息: 列类型,告知数据库要存储那种数据 渲染表单时使用的默认HTML widget 验证,被用在admin和表单中 通用字段参数(常用) nul