一、前言
之前我们说的都是orm都是一对多,今天我们来了解一下多对多关系,比如说一台主机上有多个应用,一个应用可以部署在多台主机上,类似这种情况的,多对多关系的。那我们怎么设计的表结构,那在django框架里面,这个多对多是如何建立的呐?下面我们就来学习一下。
二、创建多对多的方式
2.1、建立的多对多表关系
2.2、自定义关系表
说明:通过自己手动去定义表关系,通过看到的类去操作表关系。
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
port = models.IntegerField()
class Application(models.Model):
name = models.CharField(max_length=32)
class HostToApp(models.Model): #手动创建第三张表
host = models.ForeignKey(to="Host",to_field="nid",on_delete=models.CASCADE,)
application = models.ForeignKey(to="Application",to_field="id",on_delete=models.CASCADE,)
增加数据类似于:
HostToApp.objects.create(host_id=1,application_id=2)
2.3、自动创建关系表
说明:是第三张表关系是django自动帮我我们创建的,不需要自己去创建
class Host(models.Model):
nid = models.AutoField(primary_key=True)
hostname = models.CharField(max_length=32,db_index=True)
ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
port = models.IntegerField()
business = models.ForeignKey(to="Business",to_field="id",on_delete=models.CASCADE,)
class Application(models.Model):
name = models.CharField(max_length=32)
host = models.ManyToManyField(to="Host") #自动创建第三张表
数据库表结构生成第三表:
我因为是用内部创建的表,是无法通过类去操作数据库的,因为你看不到,所以,就用 host 这个多对多的关系字段,这个字段就相当于暴露一根线,通过它对第三张表进行操作,操作如下:
①添加(add)
obj = Application.objects.get(id=1)
obj.name #获取name字段的值
obj.host.add(2) #增加一个application_id=1,host_id=2的值
obj.host.add(1,2,3) #增加application_id=1,host_id=1的值,application_id=1,host_id=2的值,application_id=1,host_id=3的值
obj.host.add(*[1,2,3]) #增加多个关系,可以传入一个列表,和上面一样
②删除(remove)
obj = Application.objects.get(id=1)
obj.name #获取name字段的值
obj.host.remove(2) #删除一个application_id=1,host_id=2的值
obj.host.remove(1,2,3) #删除application_id=1,host_id=1的值,application_id=1,host_id=2的值,application_id=1,host_id=3的值
obj.host.remove(*[1,2,3]) #删除多个关系,可以传入一个列表,和上面一样
③清除(clear)
obj = Application.objects.get(id=1)
obj.host.clear() #清除application_id=1的所有数据记录
④ 设置(set)
obj = Application.objects.get(id=1)
obj.host.set([1,3]) #这边列表前面没有*,数据库只保存host_id=1,application_id=1;host_id=1,application_id=3的数据,其他的全部清除
⑤获取另外一张表(Host)符合条件的对象
说明:拿到的是QuerySet类型的,里面是另外一张表(Host)的对象
obj = Application.objects.get(id=1)
# Application.objects后面能加什么,obj.host后面就能加什么
obj.host.all() #application_id对应的host_id有10个,那么就会把符合条件的Host对象全部拿到,也就是说所有相关主句对象'列表'
如图:
三、增加示例
3.1、正常的form表单提交
1、urls.py的增加
说明:增加一个url,这个url叫app
from django.urls import path,re_path
from app01 import views
urlpatterns = [
re_path('^app/$',views.app)
]
2、templates用form提交方式:
1 <head> 2 <meta charset="UTF-8"> 3 <title>Title</title> 4 <style> 5 .host-tag{ 6 display: inline-block; 7 padding: 3px; 8 border: 1px solid red; 9 background-color: palevioletred; 10 } 11 .hide{ 12 display: none; 13 } 14 .shade{ 15 position: fixed; 16 top:0; 17 right:0; 18 left:0; 19 bottom: 0; 20 background: black; 21 opacity: 0.6; 22 z-index: 100; 23 } 24 .add-modal{ 25 position: fixed; 26 height: 300px; 27 width: 400px; 28 top:200px; 29 left: 50%; 30 z-index: 101; 31 border: 1px solid white; 32 background: white; 33 margin-left: -200px; 34 } 35 </style> 36 </head> 37 <body> 38 <h1>应用列表</h1> 39 <div> 40 <input id="add_host" type="button" value="添加"/> 41 </div> 42 <table border="1"> 43 <thead> 44 <tr> 45 <td>应用名称</td> 46 <td>应用主机列表</td> 47 </tr> 48 </thead> 49 <tbody> 50 {% for app in app_list %} 51 <tr> 52 <td>{{ app.name }}</td> 53 <td> 54 {% for host in app.host.all %} 55 <span class="host-tag">{{ host.hostname }}</span> 56 {% endfor %} 57 </td> 58 </tr> 59 {% endfor %} 60 </tbody> 61 </table> 62 <div class="shade hide"></div> 63 <div class="add-modal hide"> 64 <form id="add_form" method="post" action="/app/"> 65 <div class="group"> 66 <input id="app_name" type="text" placeholder="应用名称" name="app_name"> 67 </div> 68 <div class="group"> 69 <select id="sel" name="host_list" multiple> 70 {% for op in host_list %} 71 <option value="{{ op.nid }}">{{ op.hostname }}</option> 72 {% endfor %} 73 </select> 74 </div> 75 <input type="submit" value="提交"> 76 <input id="cancel" type="button" value="取消"> 77 </form> 78 </div> 79 80 <script src="/static/jquery-1.12.4.js"></script> 81 <script> 82 $(function(){ 83 $("#add_host").click(function(){ 84 $(".shade,.add-modal").removeClass("hide"); 85 }); 86 87 $("#cancel").click(function(){ 88 $(".shade,.add-modal").addClass("hide"); 89 }); 90 }) 91 </script> 92 </body>
3、view.py的后台代码处理
def app(request):
if request.method == "GET":
app_list = models.Application.objects.all()
host_list = models.Host.objects.all()
return render(request,"app.html",{'app_list':app_list,'host_list':host_list})
elif request.method == "POST":
app_name = request.POST.get("app_name")
host_list = request.POST.getlist("host_list")
print(app_name,host_list,sep="\t")
#创建完了,会返回一个对象,这个对象就是你刚增加完的这条数据的对象
obj = models.Application.objects.create(name=app_name)
obj.host.add(*host_list)
return redirect("/app/")
3.2、用ajax方式提交
说明:这边我提交到一个行的url上去,跟上面区别开来
1、urls.py的代码
from django.urls import path,re_path
from app01 import views
urlpatterns = [
re_path('^ajax_add_app/$',views.ajax_add_app)
]
2、templates用ajax提交方式:
1 <head> 2 <meta charset="UTF-8"> 3 <title>Title</title> 4 <style> 5 .host-tag{ 6 display: inline-block; 7 padding: 3px; 8 border: 1px solid red; 9 background-color: palevioletred; 10 } 11 .hide{ 12 display: none; 13 } 14 .shade{ 15 position: fixed; 16 top:0; 17 right:0; 18 left:0; 19 bottom: 0; 20 background: black; 21 opacity: 0.6; 22 z-index: 100; 23 } 24 .add-modal{ 25 position: fixed; 26 height: 300px; 27 width: 400px; 28 top:200px; 29 left: 50%; 30 z-index: 101; 31 border: 1px solid white; 32 background: white; 33 margin-left: -200px; 34 } 35 </style> 36 </head> 37 <body> 38 <h1>应用列表</h1> 39 <div> 40 <input id="add_host" type="button" value="添加"/> 41 </div> 42 <table border="1"> 43 <thead> 44 <tr> 45 <td>应用名称</td> 46 <td>应用主机列表</td> 47 </tr> 48 </thead> 49 <tbody> 50 {% for app in app_list %} 51 <tr> 52 <td>{{ app.name }}</td> 53 <td> 54 {% for host in app.host.all %} 55 <span class="host-tag">{{ host.hostname }}</span> 56 {% endfor %} 57 </td> 58 </tr> 59 {% endfor %} 60 </tbody> 61 </table> 62 <div class="shade hide"></div> 63 <div class="add-modal hide"> 64 <form id="add_form"> 65 <div class="group"> 66 <input id="app_name" type="text" placeholder="应用名称" name="app_name"> 67 </div> 68 <div class="group"> 69 <select id="sel" name="host_list" multiple> 70 {% for op in host_list %} 71 <option value="{{ op.nid }}">{{ op.hostname }}</option> 72 {% endfor %} 73 </select> 74 </div> 75 <input id="add_submit_ajax" type="button" value="ajax提交"> 76 <input id="cancel" type="button" value="取消"> 77 </form> 78 </div> 79 80 <script src="/static/jquery-1.12.4.js"></script> 81 <script> 82 $(function(){ 83 $("#add_host").click(function(){ 84 $(".shade,.add-modal").removeClass("hide"); 85 }); 86 87 $("#cancel").click(function(){ 88 $(".shade,.add-modal").addClass("hide"); 89 }); 90 $("#add_submit_ajax").click(function(){ 91 $.ajax({ 92 url:'/ajax_add_app/', 93 data:$("#add_form").serialize(), 94 type:"POST", 95 dataType:"JSON",//在jquery内部帮你做序列化的处理,代替了success里面的JSON.parse(data)这一步 96 traditional: true, //{'host_list':[1,2,3,4]},jquery内部帮你做处理,可是它处理不了,发到后台是none,所以这边要告诉jquery需要处理 97 success: function(obj){ //这样的话,这边就不是data了,而是obj对象 98 if(obj.status){ 99 location.reload() 100 }else { 101 console.log(obj.error) 102 } 103 }, 104 error: function(){ 105 //发送一个请求,后台没有捕捉到的,发生了一个未知的问题 106 } 107 }) 108 }); 109 }) 110 </script> 111 </body>
3、view.py代码:
def ajax_add_app(request):
import json
ret = {'status':True,'error':None,'data':None}
print(request.POST)
app_name = request.POST.get("app_name")
host_list = request.POST.getlist("host_list")
print(app_name,host_list)
obj = models.Application.objects.create(name=app_name) #创建完了,会返回一个对象,这个对象就是你刚增加完的这条数据的对象
obj.host.add(*host_list)
return HttpResponse(json.dumps(ret))
四、总结
4.1、ajax提交方式
$.ajax({
url:'URL',
data:$("#id").serialize(),
type:"POST",
dataType:"JSON",//在jquery内部帮你做序列化的处理,代替了success里面的JSON.parse(data)这一步
traditional: true, //{'host_list':[1,2,3,4]},jquery内部帮你做处理,可是它处理不了,发到后台是none,所以这边要告诉jquery需要处理
success: function(obj){ //这样的话,这边就不是data了,而是obj对象
if(obj.status){
location.reload()
}else {
console.log(obj.error)
}
},
error: function(){
//发送一个请求,后台没有捕捉到的,发生了一个未知的问题
}
})
4.2、创建多对多
host = models.ManyToManyField(to="Host")
4.3、创建第三张表数据
obj = models.Application.objects.create(name=app_name) #创建时候,返回你创建那条数据的对象
obj.host.add(*host_list) #通过这个对象去创建第三张表的数据
4.4、创建多对关系哪种方式好?
答:我觉得方式一比较好,①方式二只能帮你3列,不能创建5列,6列,加额外的数据,它做不到。②方式一:想加几列加几列,可以自定义话。
4.5、编辑数据
obj = models.Application.objects.get(id=1)
obj.name = "new_name"
obj.save() #不管多对多还是一对多,更新数据都需要这种方式
obj.host.set([1,2,3,4]) #更新第三张表需要用到set