zoukankan      html  css  js  c++  java
  • ORM中的一对一和多对多

    ORM中的一对一和多对多

    ORM 一对一

    什么时候用一对一?

    当 一张表的某一些字段查询的比较频繁,另外一些字段查询的不是特别频繁
    把不怎么常用的字段 单独拿出来做成一张表 然后用过一对一关联起来

    优势

    既保证数据都完整的保存下来,又能保证大部分的检索更快

    ORM中的用法

    OneToOneField(to="")

    示例

    在ORM中有作者这个类,类中有一个字段对应作者详情类,作者详情类中包含作者爱好和住址。
    类的代码

    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        phone = models.IntegerField()
        books = models.ManyToManyField(to="Book", related_name="authors")
        detail = models.OneToOneField(to="AuthorDetail")
    
        def __str__(self):
            return self.name
    
    
    class AuthorDetail(models.Model):
        bobby = models.CharField(max_length=32)
        addr = models.CharField(max_length=128)
    

    ORM 多对多的三种方式

    方式一:ORM自动创建第三张表

    books = models.ManyToManyField(to="Book", related_name="authors")

    在 ORM 代码中加上上面那句话,ORM 会自动创建第三张关联 Author 和 Book 的表,自动命名并且自动将字段设置为 author_id 和 book_id 。设置 related_name 是为了方便以后的查询操作。

    ORM代码

    class Book(models.Model):
        title = models.CharField(max_length=32)
        publish_date = models.DateField(auto_now_add=True)
        price = models.DecimalField(max_digits=5, decimal_places=2)
    
        publisher = models.ForeignKey(to="Publisher")
    
        def __str__(self):
            return self.title
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        phone = models.IntegerField()
        books = models.ManyToManyField(to="Book", related_name="books")
        detail = models.OneToOneField(to="AuthorDetail")
    
        def __str__(self):
            return self.name
    

    查询操作

    from app01 import models
    
    # 从app01中获取id为1的作者出的书
    ret = models.Author.objects.get(id=1).books.all()
    print(ret)
    
    # 移除作者所写书中id为1的书
    models.Author.objects.get(id=1).books.remove(1)
    ret = models.Author.objects.get(id=1).books.all()
    print(ret)
    

    方式二:自己创建第三张表, 利用外键分别关联作者和书

    关联查询比较麻烦,因为没办法使用ORM提供的便利方法

    ORM代码

    class Book(models.Model):
        title = models.CharField(max_length=32)
        publish_date = models.DateField(auto_now_add=True)
        price = models.DecimalField(max_digits=5, decimal_places=2)
    
        publisher = models.ForeignKey(to="Publisher")
    
        def __str__(self):
            return self.title
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        phone = models.IntegerField()
        detail = models.OneToOneField(to="AuthorDetail")
    
        def __str__(self):
            return self.name
    
    
    # 手动创建第三张作者和书相关联的表
    # 此时在ORM层面上,作者和书没有多对多的关系了
    class Author2Book(models.Model):
        id = models.AutoField(primary_key=True)
    
        # 作者id
        author = models.ForeignKey(to="Author")
    
        # 书id
        book = models.ForeignKey(to="Book")
    
        # 建立唯一约束
        class Meta:
            # 顺序不能变
            unique_together = ("author", "book")
    

    查询代码

    from app02 import models
    # 在app02中查询作者id为1的书
    ret = models.Author2Book.objects.filter(author_id=1).values_list("book_id")
    
    # 1. 得到所对应的书的id
    ret = [i[0] for i in ret]
    
    # 2. 从book表中将对应id的书取出来
    ret = models.Book.objects.filter(id__in=ret)
    print(ret)
    

    方式三:自己创建第三张表,使用ORM 的ManyToManyFiled()

    使用此种方式创建多对多表的时候,没有 add() remove() 等方法

    ORM代码

    class Book(models.Model):
        title = models.CharField(max_length=32)
        publish_date = models.DateField(auto_now_add=True)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        # 创建外键,关联publish
        publisher = models.ForeignKey(to="Publisher")
    
        def __str__(self):
            return self.title
    
    
    # 作者
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        phone = models.IntegerField()
        # 通过through,through_fields来指定使用我创建的第三张表来构建多对多的关系
        books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book",))
        # 第一个字段: 多对多设置在哪一张表里, 第三张表通过什么字段找到这张表 就把这个字段写在前面
        detail = models.OneToOneField(to="AuthorDetail")
    
        def __str__(self):
            return self.name
    
    
    # 自己动手 创建作者和书关联的第三张表
    # 此时 在ORM层面
    class Author2Book(models.Model):
        id = models.AutoField(primary_key=True)
        # 作者id
        author = models.ForeignKey(to="Author")
        # 书id
        book = models.ForeignKey(to="Book")
    
        # memo
        memo = models.CharField(max_length=64, null=True)
    
        class Meta:
            # 建立唯一约束
            unique_together = ("author", "book")
    

    查询代码

    from app03 import models
    # 在app03中查询作者id为1的书
    # 操作过程其实跟app01当中的一样
    ret = models.Author.objects.get(id=1).books.all()
    print(ret)
    

    我们应该用哪种?

    1. 如果你第三张表没有额外的字段,就用第一种
    2. 如果你第三张表有额外的字段,就用第三种或第一种

     

  • 相关阅读:
    小技巧:Sidebar上的Recent Posts如何排除某类别下的文章
    64位windows下,C# 访问 Lotus Domino Objects 时访问Com注册类失败原因
    ODP.net 及System.Data.OracleClient使用二三事
    收发超长短信的资料汇编
    python 3 中建立可迭代对象(making object iterable)
    悲催的PHP新型字符串
    wp下如何禁止分类列表列出某个分类
    人生的12句Comperehend领悟-感悟颇深
    RegexBuddyV3.03正则表达式工具下载
    《越狱》里玫瑰花的制作方法(超详细)
  • 原文地址:https://www.cnblogs.com/banshaohuan/p/9455664.html
Copyright © 2011-2022 走看看