• Django学习笔记一十二——建立多对多结构表的三种方式


    ManytoManyField创建表的第一种方式

    我们在前面讲了多对多关联(ManyToManyField)的使用,但是具体的使用方法都是用的直接通过ORM创建第三个表,

    第二种方法——手动创建管理表

    除了前面用ORM自动创建有关联关系的第三张表意外,我们还可以自己写,然后用外键分别关联作者和书籍

    class Books(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)

    def __str__(self): return self.title class Author(models.Model): name =models.CharField(max_length=8) #建立的第三张表 class Author2Book(models.Model): book = models.ForeignKey(to='Books',on_delete=models.CASCADE) author = models.ForeignKey(to='Author',on_delete=models.CASCADE)

    这里主要讲多对多关系的建立,把多余的字段都删除了。

    前面忘记讲了一个小知识点:我们在创建了ForeignKey关系以后,在数据库中的实际字段名称是会自动添加一个_id的,看一下这个第三张表,我们定义的名称是book和author,看看数据库里是怎么样的

     注意一点:其实这个表应该把book和author作为联合唯一约束的 ,代码如下,逻辑关系需求但是对操作表的方法没有影响。

    class Author2Book(models.Model):
        book = models.ForeignKey(to='Books',on_delete=models.CASCADE)
        author = models.ForeignKey(to='Author',on_delete=models.CASCADE)
    
        class Meta:
            unique_together = ('author','book')

    但是对于查询操作,因为我们是自己手动创建的关联表,就不能通过ORM自己查询author表或books表了,想要查谁写了什么书或者什么书的作者是谁必须从第三张表下手

    ret = models.Author2Book.objects.filter(author_id=2)
    print(ret.values())
    for i in ret:
        print(i.book.title,i.author.name)
    
    #########输出##########
    <QuerySet [{'id': 3, 'book_id': 2, 'author_id': 2}, {'id': 5, 'book_id': 4, 'author_id': 2}]>
    学习Linux 李四

    如果想查询指定作者名字的书籍更加麻烦:

    author_obj = models.Author.objects.get(name='张三')
    book_id = models.Author2Book.objects.filter(author=author_obj).values_list('book_id')
    #book_id为QuerySet对象,要获得一个list
    books_id_list = [i[0] for i in book_id]
    books = models.Books.objects.filter(id__in=books_id_list) 
    print(books)

     所以可以看出来,这种方法要比第一种方式更麻烦一些

     第三种方法

    第三种方式和上面的第二种方式差不多,都是自己手动创建第三个关系表。但是又避免了第二种方式不能用ORM提供的多对多的关系查询的弊端 

    class Books(models.Model):
        id = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)
        def __str__(self):
            return self.title
    
    class Author(models.Model):
        name =models.CharField(max_length=8)
        #通过through=..来指定使用手动创建的第三张表来建立多对多的关系
        book = models.ManyToManyField(to='Books',through='Author2Book',through_fields=('author','book')) 
    
    #建立的第三张表
    class Author2Book(models.Model):
        book = models.ForeignKey(to='Books',on_delete=models.CASCADE)
        author = models.ForeignKey(to='Author',on_delete=models.CASCADE)
    
        class Meta:
            unique_together = ('author','book')

    定义类的时候一定要注意through_fields里参数的顺序:第一个字段是多对多设置在那个表,第三张表通过什么字段找到他,就把这个字段(是第三个表里的字段)放在第一个。没有关系的字段不用写在这里

    这样建立的表,在查询数据的时候跟第一种方式是一样的。

    #正向查询
    books = models.Author.objects.get(name='张三').book.all()
    print(books)
    #反向查询
    book = models.Books.objects.get(title='学习Python')
    print(book)
    authors =book.author_set.all()
    for author in authors:
        print(author.name)

    注意

    用这种方式创建的表,是不能用前一张里说过的关联管理器中的add(),remove()等方法的。如果要进行增减,必须取到要操作的对象进行修改或删除(也就是直接对第三张表进行修改)。

    总结:什么时候用那种方式

     可以看出来第一种方式基本满足了所有的需求了,但是什么时候还要用到其他的两种方式呢?

    第三种方式其实已经包含了第二种方式,可以比较一下第一种方式的区别

    由于第一种方式是通过ORM直接说生成的关系结构表,但是有些时候我们需要在第三张表里附加一些其他的字段,第一种方式就无法满足要求了。

    比方我们要做一个婚恋网站,记录男性和女性的约会信息由于,男和女就是一个多对多的关系。约会的时间是不能放在男性表或女性表里的, 但是放在这个多对多的关系表里就可以。具体操作只说明一下思路,不放具体代码。

  • 相关阅读:
    C#基础知识简单梳理
    knearest neighbor
    二叉查找树的实现
    Unix/Linux 那些系统启动后的进程
    Nginx反向代理IIS
    线程漫谈——线程同步之信号量和互斥量
    BtxCMS@B.T.X 项目及界面展示 [下载]
    MVC in MFC or WTL
    HTTP HTTPS WebService
    ASP.NET WebAPI RC 竟然不支持最常用的json传参
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/12725448.html
Copyright © 2020-2023  润新知