Django数据表关联关系映射:一对一、一对多、多对多

数据表关联关系映射

  • 在关系型数据库中,通常不会把所有数据都放在同一张表中,这样做会额外占用内存空间,
  • 常用的表关联方式有三种:
    1. 一对一映射
      • 如: 一个身份证对应一个人
    2. 一对多映射
      • 如: 一个班级可以有多个学生
    3. 多对多映射
      • 如: 一个学生可以报多个课程,一个课程可以有多个学生学习

一对一映射

  • 一对一是表示现实事物间存在的一对一的对应关系。
  • 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
  1. 语法

    class A(model.Model):
        ...
    class B(model.Model):
        属性 = models.OneToOneField(A)
    
  2. 用法示例

    1. 创建作家和作家妻子类

      # file : xxxxxxxx/models.py
      from django.db import models
      
      class Author(models.Model):
          '''作家模型类'''
          name = models.CharField('作家', max_length=50)
      
      class Wife(models.Model):
          '''作家妻子模型类'''
          name = models.CharField("妻子", max_length=50)
          author = models.OneToOneField(Author)  # 增加一对一属性 
      
    2. 查询

      • 在 Wife 对象中,通过 author 属性找到对应的author对象
      • 在 Author 对象中,通过 wife 属性找到对应的wife对象
    3. 创始一对一的数据记录

      from . import models
      author1 = models.Author.objects.create(name='王老师')
      wife1 = models.Wife.objects.create(name='王夫人', author=author1)  # 关联王老师
      author2 = models.Author.objects.create(name='小泽老师')  # 一对一可以没有数据对应的数据 
      
    4. 一对一数据的相互获取

      1. 正向查询

        • 直接通过关联属性查询即可
        # 通过 wife 找 author
        from . import models
        wife = models.Wife.objects.get(name='王夫人')
        print(wife.name, '的老公是', wife.author.name)
        
      2. 反向查询

        • 通过反向关联属性查询
        • 反向关联属性为实例对象.引用类名(小写),如作家的反向引用为作家对象.wife
        • 当反向引用不存在时,则会触发异常
        # 通过 author.wife 关联属性 找 wife,如果没有对应的wife则触发异常
        author1 = models.Author.objects.get(name='王老师')
        print(author1.name, '的妻子是', author1.wife.name)
        author2 = models.Author.objects.get(name='小泽老师')
        try:
            print(author2.name, '的妻子是', author2.wife.name)
        except:
            print(author2.name, '还没有妻子')
        
  • 作用:

  • 主要是解决常用数据不常用数据的存储问题,把经常加载的一个数据放在主表中,不常用数据放在另一个副表中,这样在访问主表数据时不需要加载副表中的数据以提高访问速度提高效率和节省内存空间,如经常把书的内容和书名建成两张表,因为在网站上经常访问书名等信息,但不需要得到书的内容。

一对多映射

  • 一对多是表示现实事物间存在的一对多的对应关系。
  • 如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书
  1. 用法语法

    • 当一个A类对象可以关联多个B类对象时
    class A(model.Model):
        ...
    
    class B(model.Model):
        属性 = models.ForeignKey("一"的模型类, ...)
    
  2. 外键类ForeignKey

    • 构造函数:

      ForeignKey(to, on_delete, **options)
      
    • 常用参数:

      • on_delete
        1. models.CASCADE 级联删除。 Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。
        2. models.PROTECT 抛出ProtectedError 以阻止被引用对象的删除;
        3. SET_NULL 设置ForeignKey null;需要指定null=True
        4. SET_DEFAULT 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。
        5. … 其它参请参考文档 https://docs.djangoproject.com/en/1.11/ref/models/fields/#foreignkey ForeignKey部分
      • **options 可以是常用的字段选项如:
        1. null
        2. unique等
  3. 示例

    • 有二个出版社对应五本书的情况.
      1. 清华大学出版社 有书
        1. C++
        2. Java
        3. Python
      2. 北京大学出版社 有书
        1. 西游记
        2. 水浒
    # file: one2many/models.py
    from django.db import models
    class Publisher(models.Model):
        '''出版社'''
        name = models.CharField('名称', max_length=50, unique=True)
    
    class Book(models.Model):
        title = models.CharField('书名', max_length=50)
        publisher = ForeignKey(Publisher)
        
    #创建数据
    from . import models
    pub1 = models.Publisher.objects.create(name='清华大学出版社')
    models.Book.objects.create(title='C++', publisher=pub1)
    models.Book.objects.create(title='Java', publisher=pub1)
    models.Book.objects.create(title='Python', publisher=pub1) 
    
    pub2 = models.Publisher.objects.create(name='北京大学出版社')
    models.Book.objects.create(title='西游记', publisher=pub2)
    models.Book.objects.create(title='水浒', publisher=pub2)
    
    #查询
    # 通过多查一【正向查询】
    # 通过一本书找到对应的出版社 
        abook = models.Book.objects.get(id=1)
        print(abook.title, '的出版社是:', abook.publisher.name)
       
    # 通过一查多 【反向查询】
    # 通过出版社,查询对应的书
        pub1 = models.Publisher.objects.get(name='清华大学出版社')
        books = pub1.book_set.all()  # 通过book_set 获取pub1对应的多个Book数据对象
        #books = models.Book.objects.filter(publisher=pub1)  # 也可以采用此方式获取
        print("清华大学出版社的书有:")
        for book in books:
            print(book.title)
    

4.数据查询

  1. 通过 Book 查询 Publisher

    通过 publisher 属性查询即可
    book.publisher
    
  2. 通过 Publisher 查询 对应的所有的 Books

    Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用
    属性:book_set  等价于 objects
    

多对多映射

  • 多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,…),每个学校都有不同的学生…
  1. 语法

    • 在关联的两个类中的任意一个类中,增加:
    属性 = models.ManyToManyField(MyModel)
    
  2. 示例

    • 一个作者可以出版多本图书
    • 一本图书可以被多名作者同时编写
    class Author(models.Model):
        ...
    
    class Book(models.Model):
        ...
        authors = models.ManyToManyField(Author)
    
  3. 数据查询

    1. 通过 Book 查询对应的所有的 Authors

      book.authors.all() -> 获取 book 对应的所有的author的信息
      book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息
      
    2. 通过 Author 查询对应的所有的Books

      • Django会生成一个关联属性 book_set 用于表示对对应的book的查询对象相关操作
      author.book_set.all()
      author.book_set.filter()
      author.book_set.create(...)  # 创建新书并关联author
      author.book_set.add(book)   # 添加已有的书给当前作者author
      author.book_set.clear()  # 删除author所有并联的书
      
  4. 示例:

    • 多对多模型
    class Author(models.Model):
        '''作家模型类'''
        name = models.CharField('作家', max_length=50)
        def __str__(self):
            return self.name
        
    class Book(models.Model):
        title = models.CharField('书名', max_length=50)
        author = models.ManyToManyField(Author)
        def __str__(self):
       		return self.title 
    
    • 多对多视图操作
    from django.http import HttpResponse
    from . import models
    
    def many2many_init(request):
        # 创建两人个作者
        author1 = models.Author.objects.create(name='吕泽')
        author2 = models.Author.objects.create(name='王老师')
    
        # 吕择和王老师同时写了一本Python
        book11 = author1.book_set.create(title="Python")
        author2.book_set.add(book11)  #
    
        # 王老师还写了两本书
        book21 = author2.book_set.create(title="C")  # 创建一本新书"C"   
        book22 = author2.book_set.create(title="C++")  # 创建一本新书"C++"
    
        return HttpResponse("初始化成功")
    
    def show_many2many(request):
        authors = models.Author.objects.all()
        for auth in authors:
            print("作者:", auth.name, '发出版了', auth.book_set.count(), '本书: ')
            for book in books:
                print('    ', book.title)
        print("----显示书和作者的关系----")
        books = models.Book.objects.all()
        for book in books:
            auths = book.author.all()
            print(book.title, '的作者是:', '、'.join([str(x.name) for x in auths]))
        return HttpResponse("显示成功,请查看服务器端控制台终端")
    
    • 多对多最终的SQL结果
    mysql> select * from many2many_author;
    +----+-----------+
    | id | name      |
    +----+-----------+
    | 11 | 吕泽      |
    | 12 | 王老师    |
    +----+-----------+
    2 rows in set (0.00 sec)
    
    mysql> select * from many2many_book;
    +----+--------+
    | id | title  |
    +----+--------+
    | 13 | Python |
    | 14 | C      |
    | 15 | C++    |
    +----+--------+
    3 rows in set (0.00 sec)
    
    mysql> select * from many2many_book_author;
    +----+---------+-----------+
    | id | book_id | author_id |
    +----+---------+-----------+
    | 17 |      13 |        11 |
    | 20 |      13 |        12 |
    | 18 |      14 |        12 |
    | 19 |      15 |        12 |
    +----+---------+-----------+
    4 rows in set (0.00 sec)
    

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值