Python筆記18(Django之ORM(多對多))
阿新 • • 發佈:2018-08-25
方式 The short erro edm 關聯對象 對象的關聯 .site views
一、ManyToManyField
1、class RelatedManager
"關聯管理器"是在一對多或者多對多的關聯上下文中使用的管理器。
它存在於下面兩種情況:
- 外鍵關系的反向查詢
- 多對多關聯關系
簡單來說就是當 點後面的對象 可能存在多個的時候就可以使用以下的方法。
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值) --> 在原來的基礎上增加新的紀錄
Python筆記18(Django之ORM(多對多))