开发者社区> 余二五> 正文

Django 数据库表多对多的创建和增删改查

简介:
+关注继续查看

前面已经学习了在Django里面如何对单表的操作,同时也学习了1对多(单个外键)的表的操作。接下来,我们看看多对多(多个外键)的关系如何创建和管理。


比如说,我们有一个主机表,也有一个应用程序表,一个主机可以对应多个程序,一个程序也可以对应多个主机,这是一个典型的多对多的结构。一般来说,我们会在数据库里创建一个中间的表,分别和这两个表进行外键关联。


例1. 手动的定义一个HostToApp表,关联到Host和Application表,这样一来,如果我希望创建一个新的关联,我直接对这个中间的表进行操作即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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()
    = models.ForeignKey(to="Business", to_field='id')
 
class Application(models.Model):
    name = models.CharField(max_length=32)
 
class HostToApp(models.Model):
    hobj = models.ForeignKey(to='Host',to_field='nid')
    aobj = models.ForeignKey(to='Application',to_field='id')
 
#创建一个新的关联关系
HostToApp.objects.create(hobj_id=1,aobj_id=2)

例2. 除了手动创建一个关系表,我们还可以让系统自动生成一个


1
2
3
4
5
6
7
8
9
10
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()
    = models.ForeignKey(to="Business", to_field='id')
 
class Application(models.Model):
    name = models.CharField(max_length=32)
    = models.ManyToManyField("Host")


执行manage.py migrate和 manage.py migration 之后,查看数据库,可以看见自动生成了一个关系表app01_application_r, 里面有3个字段,一个id和两个外键

wKioL1l-gUfDqDrfAAD1MClx1WM422.jpg

这个自动生成的表,在Django里面不能直接像单表一样操作,因为系统并不知道他的‘存在’,因此只能通过间接的操作。


间接操作:


查询

//这里首先获取app_id=1的对象,后面的操作都是基于这个前提来的

obj=models.Application.objects.get(id=1)

obj.name

obj.r.all() //类似单表操作


增加

obj.r.add(1)  //添加app_id=1, host_id=1的记录

obj.r.add(2,3,4) //直接添加多个值

obj.r.add(*[1,2,3,4]) // 直接通过列表的格式添加多个值


删除,格式和增加一样

obj.r.remove(1)

obj.r.remove(2,3)

obj.r.remove(*[2,3,4])

obj.r.clear() //删除所有app_id=1的关系


修改

obj.r.set([2,3,4]) //直接设置app_id=1, host_id=2,3,4,注意列表前面没有星号 



例3. 下面看个实例


models.py

1
2
3
4
5
6
7
8
9
10
    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()
    = models.ForeignKey(to="Business", to_field='id')
 
class Application(models.Model):
    name = models.CharField(max_length=32)
    = models.ManyToManyField("Host")


urls.py ( 里面有 views.app和 views.ajax_add_app,对比ajax和普通使用)

1
2
3
4
5
6
7
8
9
10
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^business$', views.business),
    url(r'^host$', views.host),
    url(r'^test_ajax$', views.test_ajax),
    url(r'^app$', views.app),
    url(r'^ajax_add_app$', views.ajax_add_app),


views.py 注意获取用户输入的新的App名称和这个App所对应的主机列表,分别在不同的表进行创建新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)
        #直接obj就是创建的新数据的对象
        obj = models.Application.objects.create(name=app_name)
        #间接添加列表,前面加*
        obj.r.add(*host_list)
        return redirect('/app')
         
def ajax_add_app(request):
    ret = {'status':True'error':None'data'None}
    app_name = request.POST.get('app_name')
    host_list = request.POST.getlist('host_list')
    obj = models.Application.objects.create(name=app_name)
    obj.r.add(*host_list)
    return HttpResponse(json.dumps(ret))


app.html,主要界面是就是显示当前数据和一个模态对话框。点击添加,弹出对话框,然后输入App和对应的主机名;后台获取之后添加返回页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .host-tag{
            display: inline-block;
            padding: 3px;
            border: 1px solid red;
            background-color: palevioletred;
        }
        .hide{
            display: none;
        }
        .shade{
            position: fixed;
            top: 0;
            right: 0;
            left: 0;
            bottom: 0;
            background: black;
            opacity: 0.6;
            z-index: 100;
        }
        .add-modal,.edit-modal{
            position: fixed;
            height: 300px;
            width: 400px;
            top:100px;
            left: 50%;
            z-index: 101;
            border: 1px solid red;
            background: white;
            margin-left: -200px;
        }
    </style>
</head>
<body>
    <h1>应用列表</h1>
     <div>
        <input id="add_app" type="button" value="添加" />
    </div>
    <table border="1">
        <thead>
            <tr>
                <td>应用名称</td>
                <td>应用主机列表</td>
            </tr>
        </thead>
        <tbody>
            {% for app in app_list %}
                <tr aid="{{ app.id }}">
                    <td>{{ app.name }}</td>
                    <td>
                        {% for host in app.r.all %}
                            <span class="host-tag" hid="{{ host.nid }}"> {{ host.hostname }} </span>
                        {% endfor %}
                    </td>
                    <td>
                        <a class="edit">编辑</a>
                    </td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    <div class="shade hide"></div>
    <div class="add-modal hide">
        <form id="add_form" method="POST" action="/app">
            <div class="group">
                <input id="app_name" type="text" placeholder="应用名称" name="app_name" />
            </div>
            <div class="group">
            //multiple允许多选,发送到后台是一个列表,后台通过get_list接收
                <select id="host_list" name="host_list" multiple>
                    {% for op in host_list %}
                        <option value="{{ op.nid }}">{{ op.hostname }}</option>
                    {% endfor %}
                </select>
            </div>
            <input type="submit" value="提交" />
            <input id="add_submit_ajax" type="button" value="Ajax提交" />
        </form>
    </div>
     
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function(){
        //显示对话框
            $('#add_app').click(function(){
                $('.shade,.add-modal').removeClass('hide');
            });
        //隐藏对话框
            $('#cancel').click(function(){
                $('.shade,.add-modal').addClass('hide');
            });
        //发送一个Ajax请求,序列化的时候,可以直接通过form.serialize(),dataType指定JSON
这样就不需要获取之后再做个JSON.parse(data),如果是单个数据,后台可以直接接收,如果存在列表数据,需要指定tradtional是True        
            $('#add_submit_ajax').click(function(){
                $.ajax({
                    url: '/ajax_add_app',
                    // data: {'user': 123,'host_list': [1,2,3,4]},
                    data: $('#add_form').serialize(),
                    type: "POST",
                    dataType: 'JSON', // 内部
                    traditional: true,
                    success: function(obj){
                        console.log(obj);
                    },
                    error: function () {
                    }
                })
            });
            
        })
    </script>
</body>
</html>


结果如下所示:

wKiom1l-jHSRyfXLAAD35VHqDVU630.jpg

wKioL1l-jHWSWweBAADwlLLO5-s108.jpg

wKioL1l-jHaBfgaXAAEKbhBF4iM450.jpg


在我们使用模态对话框的时候,使用AJAX的好处是可以实现一些验证的功能;如果我们不在同一个Url里面使用模态对话框,而是新开一个URL来创建数据,可以直接用普通的form提交就行了。模态对话框适合小数据的提交,而新的Url更适合大量数据的提交(比如新开一个页面写博客)






本文转自 beanxyz 51CTO博客,原文链接:http://blog.51cto.com/beanxyz/1952243,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
linux中数据库的安装 增删改查
linux中数据库的安装 增删改查 mariadb的安装和初始化 yum install mariadb-server.x86_64 -y systemctl status mariadb systemctl s.
9945 0
如何创建最简单的 ABAP 数据库表,以及编码从数据库表中读取数据 (上) 试读版
如何创建最简单的 ABAP 数据库表,以及编码从数据库表中读取数据 (上) 试读版
29 0
MySql数据库增删改查常用语句命令-MySQL步骤详解教程
根据查询结果返回一个正的 MySQL 结果资源号,出错时返回 FALSE。本函数会对 INSERT/UPDATE/DELETE 查询返回 TRUE/FALSE 来指示成功或失败。
54 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
25230 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
20690 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
18989 0
使用jpa在postgresql数据库中创建主键自增表
jpa依赖 org.springframework.boot spring-boot-starter-data-jpa org.
2736 0
使用Linq to Sql 创建数据库和表
1.建一个类Article View Code 1 using System.Data.Linq.Mapping; 2 3 4 5 [Table(Name = "Article")] 6 public class Article 7 { 8 ...
1036 0
+关注
20381
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载