zoukankan      html  css  js  c++  java
  • Django基础---orm数据库操作之多表操作

    创建模型

    表关系确立原则

    • 一旦确定一对多的关系:在多的表中建立关联字段
    • 一旦确定多对多的关系:创建第三章表(关联表),ID和两个关联字段
    • 一旦确定一对一的关系:在两张表中的任意一张建立关联字段+unique

    实例:我们来假定下面这些概念,字段和关系

    作者模型:一个作者有姓名和年龄。

    作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

    出版商模型:出版商有名称,所在城市以及email。

    书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

    模型建立如下:

    from django.db import models
    
    # Create your models here.
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True) # 自增id(可以不写,默认会有自增id)
        name=models.CharField( max_length=32)
        age=models.IntegerField()
    
        # 与AuthorDetail建立一对一的关系
        authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
        
    class AuthorDetail(models.Model):
    
        nid = models.AutoField(primary_key=True)
        birthday=models.DateField()
        telephone=models.BigIntegerField()
        addr=models.CharField( max_length=64)
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        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) # 一共5位,保留两位小数
    
        # 一个出版社有多本书,与Publish建立一对多的关系,外键字段建立在多的一方
        publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
        # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
        author=models.ManyToManyField(to='Author',)
    

    注意事项:

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

    添加表记录

    一对多: 对应本文例子 出版社(一)书(多)

    方式1:
       publish_obj=Publish.objects.get(nid=1)
       book_obj=Book.objects.create(title='鹿鼎记',publishDate='2008-1-13',price=100,publish=publish_obj)
    
    方式2:
       book_obj=Book.objects.create(title="笑傲江湖",publishDate="2012-12-12",price=100,publish_id=1)  
    

    核心:book_obj.publish与book_obj.publish_id是什么?

    多对多: 对应本文例子 作者

    book_obj=Book.objects.create(title='天龙八部',publishDate='2009-1-3',price=200,publish_id=2)
    wang=Author.objects.get(name='wang')
    li=Author.objects.get(name='li')
    book_obj.author.add(wang,li)
    

    核心:book_obj.author.all()是什么?

    book_obj.author.all()是一个queryset: <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]

    多对多关系其它常用API:

    book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])
    book_obj.authors.clear()       #清空被关联对象集合
    book_obj.authors.set()         #先清空再设置  
    

    基于对象的跨表查询

    一对多(Publish 与 Book)

    ​ book_obj.publish

    Book(关联属性publish)----------------------------------------> Publish

    ​ publish_obj.book_set.all() #queryset

    正向查询:按字段 publish

        book_obj = Book.objects.filter(pk=2).first()
        print(book_obj.publish.city)
    

    反向查询:按表名小写_set.all()

    publish=Publish.objects.get(name="苹果出版社")
    #publish.book_set.all() : 与苹果出版社关联的所有书籍对象集合
    book_list=publish.book_set.all()    
    for book_obj in book_list:
           print(book_obj.title)
    

    注意:

    你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Article model 中做一下更改:

    publish = ForeignKey(Book, related_name='bookList')
    

    那么接下来就会如我们看到这般:

    # 查询 人民出版社出版过的所有书籍
     
    publish=Publish.objects.get(name="人民出版社")
    book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合
    

    一对一查询(Author 与 AuthorDetail)

    ​ author.authordetail

    Author(关联属性AuthorDetail)----------------------------------------> AuthorDetail对象

    ​ authordetail.author

    正向查询: 按字段 authorDetail

        author_obj=Author.objects.filter(name='wang').first()
        ad=author_obj.authorDetail.addr
    

    反向查询:按表名小写(没有_set)

        aurhord_obj=AuthorDetail.objects.filter(addr='北京').first()
        author=aurhord_obj.author
        print(author.name)
    

    多对多查询 (Author 与 Book)

    ​ book_obj.author.all()

    Book(关联属性Author)对象 ----------------------------------------> Author对象

    ​ author.book_set.all() # queryset

    正向查询: 按字段 author

        book_obj=Book.objects.get(title='天龙八部')
        print(book_obj)
        authors=book_obj.author.all()
        print(authors)
        for author_obj in authors:
            print(author_obj.name,author_obj.aurhorDetail.telephone)
    

    反向查询: 按表名 book_set

        author_obj=Author.objects.get(name='wang')
        books=author_obj.book_set.all()
        for i in books:
            print(i.title)
    

    基于双下划线的跨表查询

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

    正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表

    一对多查询

    # 练习:  查询苹果出版社出版过的所有书籍的名字与价格(一对多)
    # 正向查询 按字段:publish
        ret=Book.objects.filter(publish__name='苹果出版社').values_list('title','price')
        print(ret)
    
    # <QuerySet [('笑傲江湖', Decimal('100.00')), ('鹿鼎记', Decimal('100.00'))]>
    
    # 反向查询 按表名:book
        ret=Publish.objects.filter(name='苹果出版社').values_list('book__title','book__price')
        print(ret)
    

    多对多查询

    # 练习: 查询li出过的所有书籍的名字(多对多)
    # 正向查询 按字段:author
        ret=Book.objects.filter(author__name='li').values('title')
        print(ret)
        
    # 反向查询 按表名:book
        ret=Author.objects.filter(name='li').values('book__title')
        print(ret)
    

    一对一查询

    # 查询alex的手机号
    # 正向查询
    	ret=Author.objects.filter(name='li').values('aurhorDetail__telephone')
    
    # 反向查询
        ret=AuthorDetail.objects.filter(author__name="alex").values("telephone")
    

    进阶练习(连续跨表)

    # 练习: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    # 正向查询
    ret=Book.objects.filter(publish__name='人民出版社').values('author__name','publish__book__price')
    
    # 反向查询
    ret=Publish.objects.filter(name='人民出版社').values('book__author__name','book__price')
    
    # 练习: 手机号以183开头的作者出版过的所有书籍名称以及出版社名称
    # 正向查询
    ret=Book.objects.filter(author__authorDetail__telephone__regex="183").values_list("title","publish__name")
    
    # 反向查询
    ret=Author.objects.filter(aurhorDetail__telephone__startswith='183').values('book__publish__name','book__title')
    
  • 相关阅读:
    AutoCAD LISP 循环选择语句cond
    AutoCAD LISP利用子程序绘制田字格
    java.lang.ClassNotFoundException: org.springframework.web.util.Log4jConfigListen
    java.lang.IllegalArgumentException: node to traverse cannot be null!
    扩展jQuery easyui datagrid增加动态改变列编辑的类型
    eclipse管理多个workspace(转载)
    JBPM4 No unnamed transitions were found for the task 'XXXX'
    MySQL 日期计算
    jbpm与spring整合不停显示查询语句select jobimpl0_.DBID_ as DBID1_6_, jobimpl0_.DBVERSION_ as DBVERSION3_6_......
    在可编辑datagrid中,使用my97日期控件
  • 原文地址:https://www.cnblogs.com/peitianwang/p/14311093.html
Copyright © 2011-2022 走看看