一、ManyToManyField
1、class RelatedManager
"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。
它存在于下面两种情况:
- 外键关系的反向查询
- 多对多关联关系
简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。
2、方法
1)create()
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。
1>>> import datetime 2>>> models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())
2)add()
把指定的model对象添加到关联对象集中。
1# 添加对象 2>>> author_objs = models.Author.objects.filter(id__lt=3) 3>>> models.Book.objects.first().authors.add(*author_objs) 4 5# 添加id 6>>> models.Book.objects.first().authors.add(*[1, 2])
3)set()
更新model对象的关联对象。
1>>> book_obj = models.Book.objects.first() 2>>> book_obj.authors.set([2, 3])
4)remove()
从关联对象集中移除执行的model对象。
1>>> book_obj = models.Book.objects.first() 2>>> book_obj.authors.remove(3)
5)clear()
从关联对象集中移除一切对象。
1>>> book_obj = models.Book.objects.first() 2>>> book_obj.authors.clear()
注意:
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
示例:
1# ForeignKey字段没设置null=True时, 2class Book(models.Model): 3 title = models.CharField(max_length=32) 4 publisher = models.ForeignKey(to=Publisher) 5 6# 没有clear()和remove()方法: 7>>> models.Publisher.objects.first().book_set.clear() 8Traceback (most recent call last): 9 File "<input>", line 1, in <module> 10AttributeError: 'RelatedManager' object has no attribute 'clear' 11 12# 当ForeignKey字段设置null=True时, 13class Book(models.Model): 14 name = models.CharField(max_length=32) 15 publisher = models.ForeignKey(to=Class, null=True) 16 17# 此时就有clear()和remove()方法: 18>>> models.Publisher.objects.first().book_set.clear()
4、书籍与作者多对多举例

1from django.db import models 2 3 4# Create your models here. 5 6 7class Publisher(models.Model): 8 name = models.CharField(max_length=12) 9 10 11# 书籍表 12class Book(models.Model): 13 title = models.CharField(max_length=32) 14 publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE) 15 16 17# 作者表 18class Author(models.Model): 19 name = models.CharField(max_length=12) 20 # 多对多,自动帮我们在数据库建立第三张关系表 21 books = models.ManyToManyField(to='Book', related_name="authors")
models.py

1from django.conf.urls import url 2from django.contrib import admin 3from app01 import views 4 5urlpatterns = [ 6 url(r'^admin/', admin.site.urls), 7 url(r'^author_list/$', views.author_list), 8 url(r'^delete_author/(\d+)/$', views.delete_author), 9 url(r'^add_author/$', views.AddAuthor.as_view()), 10 url(r'^edit_author/(\d+)/$', views.EditAuthor.as_view()), 11]
urls.py

1from django.shortcuts import render, redirect, HttpResponse 2from app01 import models 3from django import views 4 5 6# Create your views here. 7 8 9def author_list(request): 10 author_list = models.Author.objects.all() 11 return render(request, "author_list.html", {"data": author_list}) 12 13 14def delete_author(request, delete_id): 15 # models.Author.objects.get(id=delete_id) # 很少用,谨慎使用 16 models.Author.objects.filter(id=delete_id).delete() 17 return redirect("/author_list/") 18 19 20# 添加作者 21class AddAuthor(views.View): 22 23 def get(self, request): 24 book_list = models.Book.objects.all() 25 return render(request, "add_author.html", {"book_list": book_list}) 26 27 def post(self, request): 28 print(request.POST) 29 # 用户新创建的作者名字 30 author_name = request.POST.get("name") 31 # 用户给新作者设置的书名id, 因为是多选所以要用getlist取值 32 books_ids = request.POST.getlist("books") 33 print(author_name, books_ids) 34 # 1. 先创建一个新的作者对象 35 author_obj = models.Author.objects.create(name=author_name) 36 # 2. 去第三张关系表,建立关系记录 37 author_obj.books.set(books_ids) 38 return redirect("/author_list/") 39 # return HttpResponse("OK") 40 41 42class EditAuthor(views.View): 43 def get(self, request, edit_id): 44 author_obj = models.Author.objects.filter(id=edit_id).first() 45 book_list = models.Book.objects.all() 46 return render(request, "edit_author.html", {"author": author_obj, "book_list": book_list}) 47 48 def post(self, request, edit_id): 49 author_obj = models.Author.objects.filter(id=edit_id).first() 50 51 new_name = request.POST.get("name") 52 new_books = request.POST.getlist("books") 53 54 # 真正的更新操作 55 author_obj.name = new_name 56 author_obj.save() 57 58 author_obj.books.set(new_books) 59 return redirect("/author_list/")
views.py

1{#author_list.html#} 2 3<!DOCTYPE html> 4<html lang="en"> 5<head> 6 <meta charset="UTF-8"> 7 <title>作者列表</title> 8</head> 9<body> 10 11<table border="1"> 12 <thead> 13 <tr> 14 <th>#</th> 15 <th>id</th> 16 <th>作者名字</th> 17 <th>写过的书</th> 18 <th>操作</th> 19 </tr> 20 </thead> 21 22 <tbody> 23 {% for author in data %} 24 <tr> 25 <td>{{ forloop.counter }}</td> 26 <td>{{ author.id }}</td> 27 <td>{{ author.name }}</td> 28 <td>{% for book in author.books.all %}{{ book.title }},{% endfor %}</td> 29 <td> 30 <a href="/delete_author/{{ author.id }}/">删除</a> 31 <a href="/edit_author/{{ author.id }}/">编辑</a> 32 </td> 33 </tr> 34 {% endfor %} 35 36 </tbody> 37</table> 38</body> 39</html> 40 41{#edit_author.html#} 42 43<!DOCTYPE html> 44<html lang="en"> 45<head> 46 <meta charset="UTF-8"> 47 <title>编辑作者</title> 48</head> 49<body> 50 51<form action="" method="post"> 52 {% csrf_token %} 53 <p>作者名: 54 <input type="text" name="name" value="{{ author.name }}"> 55 </p> 56 <p>书名: 57 <select name="books" multiple> 58 {% for book in book_list %} 59 <!-- 如果当前for循环的这本书在作者关联的书的列表里面 --> 60 {% if book in author.books.all %} 61 <option selected value="{{ book.id }}">{{ book.title }}</option> 62 <!-- 否则 --> 63 {% else %} 64 <option value="{{ book.id }}">{{ book.title }}</option> 65 {% endif %} 66 {% endfor %} 67 </select> 68 </p> 69 <p> 70 <input type="submit" value="提交"> 71 </p> 72 73</form> 74</body> 75</html> 76 77{#add_author.html#} 78 79<!DOCTYPE html> 80<html lang="en"> 81<head> 82 <meta charset="UTF-8"> 83 <title>添加作者</title> 84</head> 85<body> 86 87<form action="" method="post"> 88 {% csrf_token %} 89 <p>作者名: 90 <input type="text" name="name"> 91 </p> 92 <p>书名: 93 <select name="books" multiple> 94 {% for book in book_list %} 95 <option value="{{ book.id }}">{{ book.title }}</option> 96 {% endfor %} 97 </select> 98 </p> 99 <p> 100 <input type="submit" value="提交"> 101 </p> 102 103 104 <p> 105 爱好: 106 <input type="checkbox" value="basketball" name="hobby">篮球 107 <input type="checkbox" value="football" name="hobby">足球 108 <input type="checkbox" value="doublecolorball" name="hobby">双色球 109 </p> 110</form> 111</body> 112</html>
html代码
5、基于对象和QuerySet查询
1import os 2 3 4if __name__ == '__main__': 5 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings") 6 7 import django 8 django.setup() 9 10 from app01 import models 11 12 author_obj = models.Author.objects.first() 13 # 多对多的正向查询 14 ret = author_obj.books.all() 15 print(ret) 16 #多对多的反向查询 17 book_obj = models.Book.objects.last() 18 # 默认按照表名(全小写)_set.all() 19 # ret = book_obj.author_set.all() 20 # 如果多对多字段设置了related_name属性,反向查询的时候就按该属性值来查询 21 ret = book_obj.authors.all() 22 print(ret) 23 24 # add方法 25 author_obj = models.Author.objects.first() 26 ret = author_obj.books.all() 27 print(ret) 28 # 给作者加一本关联的书籍 29 author_obj.books.set([2, 3]) 30 author_obj.books.add(2) 31 ret = author_obj.books.all() 32 print(ret) 33 34 #查询第一个作者写过的书的名字 35 #1. 基于对象的查询 36 ret = models.Author.objects.first().books.all().values("title") 37 print(ret) 38 #基于QuerySet的双下划线查询 39 ret = models.Author.objects.filter(id=2).values("books__title") 40 print(ret) 41 42 #基于QuerySet的双下划线的反向查询 43 #由书找作者 44 ret = models.Book.objects.filter(id=2).values("authors__name") 45 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值) --> 在原来的基础上增加新的纪录