zoukankan      html  css  js  c++  java
  • Django之ORM(多对多)

    一、ManyToManyField

    1、class RelatedManager

    "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。

    它存在于下面两种情况:

    1. 外键关系的反向查询
    2. 多对多关联关系

    简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。

    2、方法

    1)create()

    创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。

    >>> import datetime
    >>> models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())

    2)add()

    把指定的model对象添加到关联对象集中。

    # 添加对象
    >>> author_objs = models.Author.objects.filter(id__lt=3)
    >>> models.Book.objects.first().authors.add(*author_objs)
    
    # 添加id
    >>> models.Book.objects.first().authors.add(*[1, 2])

    3)set()

    更新model对象的关联对象。

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.set([2, 3])

    4)remove()

    从关联对象集中移除执行的model对象。

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.remove(3)

    5)clear()

    从关联对象集中移除一切对象。

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.clear()

    注意:

    对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

    示例:

    复制代码
    # ForeignKey字段没设置null=True时,
    class Book(models.Model):
        title = models.CharField(max_length=32)
        publisher = models.ForeignKey(to=Publisher)
    
    # 没有clear()和remove()方法:
    >>> models.Publisher.objects.first().book_set.clear()
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    AttributeError: 'RelatedManager' object has no attribute 'clear'
    
    # 当ForeignKey字段设置null=True时,
    class Book(models.Model):
        name = models.CharField(max_length=32)
        publisher = models.ForeignKey(to=Class, null=True)
    
    # 此时就有clear()和remove()方法:
    >>> models.Publisher.objects.first().book_set.clear()
    复制代码

    4、书籍与作者多对多举例

    from django.db import models
    
    
    # Create your models here.
    
    
    class Publisher(models.Model):
        name = models.CharField(max_length=12)
    
    
    # 书籍表
    class Book(models.Model):
        title = models.CharField(max_length=32)
        publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)
    
    
    # 作者表
    class Author(models.Model):
        name = models.CharField(max_length=12)
        # 多对多,自动帮我们在数据库建立第三张关系表
        books = models.ManyToManyField(to='Book', related_name="authors")
    models.py
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^author_list/$', views.author_list),
        url(r'^delete_author/(d+)/$', views.delete_author),
        url(r'^add_author/$', views.AddAuthor.as_view()),
        url(r'^edit_author/(d+)/$', views.EditAuthor.as_view()),
    ]
    urls.py
    from django.shortcuts import render, redirect, HttpResponse
    from app01 import models
    from django import views
    
    
    # Create your views here.
    
    
    def author_list(request):
        author_list = models.Author.objects.all()
        return render(request, "author_list.html", {"data": author_list})
    
    
    def delete_author(request, delete_id):
        # models.Author.objects.get(id=delete_id)  # 很少用,谨慎使用
        models.Author.objects.filter(id=delete_id).delete()
        return redirect("/author_list/")
    
    
    # 添加作者
    class AddAuthor(views.View):
    
        def get(self, request):
            book_list = models.Book.objects.all()
            return render(request, "add_author.html", {"book_list": book_list})
    
        def post(self, request):
            print(request.POST)
            # 用户新创建的作者名字
            author_name = request.POST.get("name")
            # 用户给新作者设置的书名id, 因为是多选所以要用getlist取值
            books_ids = request.POST.getlist("books")
            print(author_name, books_ids)
            # 1. 先创建一个新的作者对象
            author_obj = models.Author.objects.create(name=author_name)
            # 2. 去第三张关系表,建立关系记录
            author_obj.books.set(books_ids)
            return redirect("/author_list/")
            # return HttpResponse("OK")
    
    
    class EditAuthor(views.View):
        def get(self, request, edit_id):
            author_obj = models.Author.objects.filter(id=edit_id).first()
            book_list = models.Book.objects.all()
            return render(request, "edit_author.html", {"author": author_obj, "book_list": book_list})
    
        def post(self, request, edit_id):
            author_obj = models.Author.objects.filter(id=edit_id).first()
    
            new_name = request.POST.get("name")
            new_books = request.POST.getlist("books")
    
            # 真正的更新操作
            author_obj.name = new_name
            author_obj.save()
    
            author_obj.books.set(new_books)
            return redirect("/author_list/")
    views.py
    {#author_list.html#}
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>作者列表</title>
    </head>
    <body>
    
    <table border="1">
        <thead>
        <tr>
            <th>#</th>
            <th>id</th>
            <th>作者名字</th>
            <th>写过的书</th>
            <th>操作</th>
        </tr>
        </thead>
    
        <tbody>
        {% for author in data %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ author.id }}</td>
                <td>{{ author.name }}</td>
                <td>{% for book in author.books.all %}{{ book.title }},{% endfor %}</td>
                <td>
                    <a href="/delete_author/{{ author.id }}/">删除</a>
                    <a href="/edit_author/{{ author.id }}/">编辑</a>
                </td>
            </tr>
        {% endfor %}
    
        </tbody>
    </table>
    </body>
    </html>
    
    {#edit_author.html#}
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>编辑作者</title>
    </head>
    <body>
    
    <form action="" method="post">
        {% csrf_token %}
        <p>作者名:
            <input type="text" name="name" value="{{ author.name }}">
        </p>
        <p>书名:
            <select name="books" multiple>
                {% for book in book_list %}
                    <!-- 如果当前for循环的这本书在作者关联的书的列表里面 -->
                    {% if book in author.books.all %}
                        <option selected value="{{ book.id }}">{{ book.title }}</option>
                        <!-- 否则 -->
                    {% else %}
                        <option value="{{ book.id }}">{{ book.title }}</option>
                    {% endif %}
                {% endfor %}
            </select>
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    
    </form>
    </body>
    </html>
    
    {#add_author.html#}
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>添加作者</title>
    </head>
    <body>
    
    <form action="" method="post">
        {% csrf_token %}
        <p>作者名:
            <input type="text" name="name">
        </p>
        <p>书名:
            <select name="books" multiple>
                {% for book in book_list %}
                    <option value="{{ book.id }}">{{ book.title }}</option>
                {% endfor %}
            </select>
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    
    
        <p>
            爱好:
            <input type="checkbox" value="basketball" name="hobby">篮球
            <input type="checkbox" value="football" name="hobby">足球
            <input type="checkbox" value="doublecolorball" name="hobby">双色球
        </p>
    </form>
    </body>
    </html>
     
    html代码

    5、基于对象和QuerySet查询

    复制代码
    import os
    
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
    
        import django
        django.setup()
    
        from app01 import models
    
        author_obj = models.Author.objects.first()
        # 多对多的正向查询
        ret = author_obj.books.all()
        print(ret)
        #多对多的反向查询
        book_obj = models.Book.objects.last()
        # 默认按照表名(全小写)_set.all()
        # ret = book_obj.author_set.all()
        # 如果多对多字段设置了related_name属性,反向查询的时候就按该属性值来查询
        ret = book_obj.authors.all()
        print(ret)
    
       # add方法
        author_obj = models.Author.objects.first()
        ret = author_obj.books.all()
        print(ret)
        # 给作者加一本关联的书籍
        author_obj.books.set([2, 3])
        author_obj.books.add(2)
        ret = author_obj.books.all()
        print(ret)
    
        #查询第一个作者写过的书的名字
        #1. 基于对象的查询
        ret = models.Author.objects.first().books.all().values("title")
        print(ret)
        #基于QuerySet的双下划线查询
        ret = models.Author.objects.filter(id=2).values("books__title")
        print(ret)
    
        #基于QuerySet的双下划线的反向查询
        #由书找作者
        ret = models.Book.objects.filter(id=2).values("authors__name")
        print(ret)
    复制代码

    6、总结

    ORM(多对多)
      1. ORM多对多字段
        # 多对多,自动帮我们在数据库建立第三张关系表
        books = models.ManyToManyField(to='Book', related_name="authors")
        参数:
          - to:表示和哪张表建立多对多的关系
          - related_name:表示返乡查询时使用的那个字段名,默认反向查询时使用表名_set的方式
      
      2. 多对多字段的方法
        1. 查询
           .all()  --> 多对多查询的方法,
       
        2. 删除
       
        3. 添加新作者
          1. 当form表单提交的数据是列表(多选的select多选的checkbox)取值?
          request.POST.getlist("hobby")
     
          2. .set([id1,id2,...])  参数是一个列表  --> 删除原来的设置新的
          3. .add(id值)                           --> 在原来的基础上增加新的纪录

  • 相关阅读:
    Pyhon的json库常用方法
    常用的Python操作
    Leetcode: 1301.Number of Paths with Max Score
    redis 源码阅读杂记
    二分查找性能试验
    leetcode: 600. Non-negative Integers without Consecutive Ones
    Leetcode: 902. Numbers At Most N Given Digit Set
    leetcode:956. Tallest Billboard
    innodb 插入性能简单测试
    redis 源码阅读之 redis.c
  • 原文地址:https://www.cnblogs.com/Nopeeee/p/10477535.html
Copyright © 2011-2022 走看看