【python】-- Django ORM(进阶)

Django ORM(进阶)

 上一篇博文简述了Django ORM的单表操作,在本篇博文中主要简述Django ORM的连表操作。

一、一对多:models.ForeignKey()

应用场景:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择), 例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等

 1 ForeignKey(ForeignObject) # ForeignObject(RelatedField)
 2         to,                         # 要进行关联的表名
 3         to_field=None,              # 要关联的表中的字段名称
 4         on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为
 5                                         - models.CASCADE,删除关联数据,与之关联也删除
 6                                         - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
 7                                         - models.PROTECT,删除关联数据,引发错误ProtectedError
 8                                         - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
 9                                         - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
10                                         - models.SET,删除关联数据,
11                                                       a. 与之关联的值设置为指定值,设置:models.SET(值)
12                                                       b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
13 
14                                                         def func():
15                                                             return 10
16 
17                                                         class MyModel(models.Model):
18                                                             user = models.ForeignKey(
19                                                                 to="User",
20                                                                 to_field="id"
21                                                                 on_delete=models.SET(func),)
22         related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
23         related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
24         limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
25                                     # 如:
26                                             - limit_choices_to={'nid__gt': 5}
27                                             - limit_choices_to=lambda : {'nid__gt': 5}
28 
29                                             from django.db.models import Q
30                                             - limit_choices_to=Q(nid__gt=10)
31                                             - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
32                                             - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
33         db_constraint=True          # 是否在数据库中创建外键约束
34         parent_link=False           # 在Admin中是否显示关联数据
35 
36 models.ForeignKey()函数的主要参数
models.ForeignKey()函数的主要参数
 1 一对多:
 2 def func():
 3         
 4     return 5
 5 
 6 
 7 class UserType(models.Model):
 8     name = models.CharField(max_length=32)
 9     
10 
11 class User(models.Model):
12     name = models.CharField(max_length=32)
13     pwd = models.CharField(max_length=32)
14     ut = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func))
15 
16 # delete from user where id=1
17 # delete from UserType where id=1 # 报错
18 
19 # UserType.objects.filter(id=1).delete()
20 
21 
22 
23 # 正向
24 # v = User.objects.all()
25 # for item in v:
26 #     item.user
27 #     item.pwd
28 #     item.ut.name
29 # User.objects.all().values('user','ut__name')
30 
31 # 反向
32 # v = UserType.objects.all()
33 # for item in v:
34 #     item.name
35 #     item.id
36 #     item.user_set.all() #user_set是通过对象进行反向查找
37 # models.UserType.objects.all().values('name','user__pwd') #user_pwd是在values中通过pwd条件进行反向查找
38 
39 ### related_name演示:
40 #添加related_name参数后
41 ut = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func),related_name="a")
42 #通过对象进行反向查找,将会"a"进行替代“表名_set”
43 item.a.all() #替换item.user_set.all()
44 
45 related_query_name演示:
46 #添加related_query_name参数后
47 ut = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func),related_query_name="b")
48 #对象反向查找,将会"b_set"进行替代“表名_set”,条件反向查询时,将会以“b_字段"代替表名"字段"
49 item.b_set.all() #替换item.user_set.all()
50 models.UserType.objects.all().values('name','b__pwd') #替换models.UserType.ob jects.all().values('name','user__pwd')
正向、反向查询、related演示

1、创建一对多表结构:

from django.db import models


class Business(models.Model):
    caption = models.CharField(max_length=32)
    code = models.CharField(max_length=32)


class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32, db_index=True)
    # 默认为protocol="both",即支持ipv4,也支持ipv协议
    ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
    port = models.IntegerField()
    # on_delete=models.SET_NULL 意思为:可为空的 ForeignKey ,他引用关联的对象被删除时,该项为空,前提是set null=True
    b = models.ForeignKey(to="Business", to_field='id', null=True, on_delete=models.SET_NULL)

 2、一对多表结构操作示例:

在前端页面对host列表进行主机展示、添加、编辑、删除管理,从而演示一对多表结构的增删查改操作。

1、app中的urls.py:

1 from django.conf.urls import url
2 from app1 import views
3 urlpatterns = [
4     url(r'^host$', views.host),
5     url(r'^test_ajax$', views.test_ajax),
6     url(r'^edit$', views.edit),
7     url(r'^del$', views.delete),
8 ]
app中urls.py的路由规则

2、templates:

为了演示方便,没有对host.html进行结构、样式相分离的操作(行为已分离)。

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title></title>
  6     <style>
  7         .hide {
  8             display: none;
  9         }
 10 
 11         .shade {
 12             position: fixed;
 13             top: 0;
 14             right: 0;
 15             left: 0;
 16             bottom: 0;
 17             background: black;
 18             opacity: 0.6;
 19             z-index: 100;
 20         }
 21 
 22         .add-modal, .edit-modal {
 23             position: fixed;
 24             height: 300px;
 25              400px;
 26             top: 100px;
 27             left: 50%;
 28             z-index: 101;
 29             border: 1px solid red;
 30             background: white;
 31             margin-left: -200px;
 32         }
 33     </style>
 34 </head>
 35 <body>
 36 <h1>主机列表(对象)</h1>
 37 
 38 <div>
 39     <input id="add_host" type="button" value="添加"/>
 40 </div>
 41 <table border="1">
 42     <thead>
 43     <tr>
 44         <th>序号</th>
 45         <th>主机名</th>
 46         <th>IP</th>
 47         <th>端口</th>
 48         <th>业务线名称</th>
 49         <th>操作</th>
 50     </tr>
 51     </thead>
 52     <tbody>
 53 
 54     {% for row in v1 %}
 55         <tr h_id="{{ row.nid }}" b_id="{{ row.b_id }}">
 56             <td>{{ forloop.counter }}</td>
 57             <td>{{ row.hostname }}</td>
 58             <td>{{ row.ip }}</td>
 59             <td>{{ row.port }}</td>
 60             <td>{{ row.b.caption }}</td>
 61             <td>
 62                 <a class="edit">编辑</a>|<a class="delete">删除</a>
 63             </td>
 64         </tr>
 65     {% endfor %}
 66 
 67 
 68     </tbody>
 69 </table>
 70 
 71 <h1>主机列表(字典)</h1>
 72 <table border="1">
 73     <thead>
 74     <tr>
 75         <th>主机名</th>
 76         <th>业务线名称</th>
 77     </tr>
 78     </thead>
 79     <tbody>
 80     {% for row in v2 %}
 81         <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
 82             <td>{{ row.hostname }}</td>
 83             <td>{{ row.b__caption }}</td>
 84         </tr>
 85     {% endfor %}
 86 
 87     </tbody>
 88 </table>
 89 <h1>主机列表(元组)</h1>
 90 <table border="1">
 91     <thead>
 92     <tr>
 93         <th>主机名</th>
 94         <th>业务线名称</th>
 95     </tr>
 96     </thead>
 97     <tbody>
 98     {% for row in v3 %}
 99         <tr hid="{{ row.0 }}" bid="{{ row.2 }}">
100             <td>{{ row.1 }}</td>
101             <td>{{ row.3 }}</td>
102         </tr>
103     {% endfor %}
104 
105     </tbody>
106 </table>
107 
108 
109 <div class="shade hide"></div>
110 <div class="add-modal hide">
111     <form id="add_form" method="POST" action="/app1/host">
112         <div class="group">
113             <input id="host" type="text" placeholder="主机名" name="hostname"/>
114         </div>
115 
116         <div class="group">
117             <input id="ip" type="text" placeholder="IP" name="ip"/>
118         </div>
119 
120         <div class="group">
121             <input id="port" type="text" placeholder="端口" name="port"/>
122         </div>
123 
124         <div class="group">
125             <select id="sel" name="b_id">
126                 {% for op in b_list %}
127                     <option value="{{ op.id }}">{{ op.caption }}</option>
128                 {% endfor %}
129             </select>
130         </div>
131 
132         <input type="submit" value="提交"/>
133         <a id="ajax_submit">悄悄提交</a>
134         <input id="cancel" type="button" value="取消"/>
135         <span id="erro_msg" style="color: red"></span>
136     </form>
137 
138 
139 </div>
140 
141 <div class="edit-modal hide">
142     <form id="edit_form" method="POST" action="app1/host">
143         <input type="text" name="nid" style="display:none"/>
144         <input type="text" placeholder="主机名" name="hostname"/>
145         <input type="text" placeholder="IP" name="ip"/>
146         <input type="text" placeholder="端口" name="port"/>
147         <select name="b_id">
148             {% for op in b_list %}
149                 <option value="{{ op.id }}">{{ op.caption }}</option>
150             {% endfor %}
151         </select>
152         <a id="ajax_submit_edit">确认编辑</a>
153     </form>
154 </div>
155 
156 
157 <script src="/static/jquery-1.12.4.js"></script>
158 <script src="/static/common.js"></script>
159 </body>
160 </html>
host.html

3、static:

在static编写JavaScript公共函数conmon.js(在编写common.js之前需要引入jQuery):

$(function () {

    //添加操作
    $('#add_host').click(function () {
        $('.shade,.add-modal').removeClass('hide');
    });

    $('#cancel').click(function () {
        $('.shade,.add-modal').addClass('hide');
    });

    $('#ajax_submit').click(function () {
        $.ajax({
            url: "/app1/test_ajax",   //url定义ajax发送请求的URL
            type: 'POST',             //type定义ajax发送请求的方法类型
            // data中则是ajax准备发送服务端的数据
            //data: {'hostname': $('#host').val(), 'ip': $('#ip').val(), 'port': $('#port').val(), 'b_id': $('#sel').val()},
            data: $('#add_form').serialize(), // 将整个form表单中的参数以字典形式发送给服务端,相比上面的写法,更加便捷
            success: function (data) {      // 服务端返回数据成功后执行的方法
                var obj = JSON.parse(data);
                if (obj.status) {
                    location.reload();       //重新加载当前页面(get形式)
                } else {
                    $('#erro_msg').text(obj.error);
                }
            }
        })
    });

    //编辑操作
    $('.edit').click(function () {
        $('.shade,.edit-modal').removeClass('hide');

        var bid = $(this).parent().parent().attr('b_id');
        var nid = $(this).parent().parent().attr('h_id');
        $('#edit_form').find('select').val(bid);
        $('#edit_form').find('input[name="nid"]').val(nid);

        $("#ajax_submit_edit").click(function () {
            $.ajax({
                url: "/app1/edit",
                type: "POST",
                data: $('#edit_form').serialize(),
                success: function (data) {
                    var obj = JSON.parse(data);
                    if (obj.status) {
                        $('.shade,.add-modal,.edit-modal').addClass('hide');
                        location.reload();
                    } else {
                        $('#erro_msg').text(obj.error);
                    }
                }
            });

        });
    })
});

//删除操作
$('.delete').click(function () {
    var nid = $(this).parent().parent().attr('h_id');
    $.ajax({
        url: "/app1/del",
        type: "POST",
        data: {"nid": nid},
        success: function (data) {
            var obj = JSON.parse(data);
            if (obj.status) {
                location.reload();
            }
        }
    });
});

4、app中的views.py:

import json
from django.shortcuts import redirect
from django.shortcuts import HttpResponse
from django.shortcuts import render
from app1 import models

def host(request):
    """
    host函数通过request区别get和post方法,如果是request是get方法,就从数据库中查询数据,然后将查询的数据返回给HTML进行渲染展示
    如果是request是post方法,就从request中提取数据,然后进行数据库添加操作
    :param request:
    :return:
    """
    if request.method == "GET":
        v1 = models.Host.objects.filter(nid__gt=0)
        v2 = models.Host.objects.filter(nid__gt=0).values('nid', 'hostname', 'b_id', 'b__caption')
        v3 = models.Host.objects.filter(nid__gt=0).values_list('nid', 'hostname', 'b_id', 'b__caption')

        b_list = models.Business.objects.all()

        return render(request, 'host.html', {'v1': v1, 'v2': v2, 'v3': v3, 'b_list': b_list})

    elif request.method == "POST":

        h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')
        models.Host.objects.create(hostname=h,
                                   ip=i,
                                   port=p,
                                   b_id=b
                                   )
        return redirect('/app1/host')


# 通过ajax方式提交数据,服务端提取数据操作后返回的示例:
def test_ajax(request):
    ret = {'status': True, 'error': None, 'data': None}
    try:
        h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')
        if h and len(h) > 5:
            models.Host.objects.create(hostname=h,
                                       ip=i,
                                       port=p,
                                       b_id=b)
        else:
            ret['status'] = False
            ret['error'] = "hostname error"
    except Exception as e:
        ret['status'] = False
        ret['error'] = "request error"
    return HttpResponse(json.dumps(ret))


# 编辑操作
def edit(request):
    ret = {'status': True, 'error': None, 'data': None}
    print(request.POST, request.method)
    try:
        nid = request.POST.get('nid')
        h = request.POST.get('hostname')
        i = request.POST.get('ip')
        p = request.POST.get('port')
        b = request.POST.get('b_id')
        models.Host.objects.filter(nid=nid).update(
            hostname=h,
            ip=i,
            port=p,
            b_id=b
        )
    except Exception as e:
            ret['status'] = False
            ret['error'] = "hostname error"
    return HttpResponse(json.dumps(ret))


# 删除操作
def delete(request):
    ret = {'status': True, 'error': None, 'data': None}
    print(request.POST)
    try:
        nid = request.POST.get('nid')
        models.Host.objects.filter(nid=nid).delete()
    except Exception as e:
            ret['status'] = False
            ret['error'] = "request error"
    return HttpResponse(json.dumps(ret))

  

二、多对多:models.ManyToManyField()

应用场景:在某表中创建一行数据是,有一个可以多选的下拉框,例如:创建用户信息,需要为用户指定多个爱好

 1  ManyToManyField(RelatedField)
 2         to,                         # 要进行关联的表名
 3         related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
 4         related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
 5         limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
 6                                     # 如:
 7                                             - limit_choices_to={'nid__gt': 5}
 8                                             - limit_choices_to=lambda : {'nid__gt': 5}
 9 
10                                             from django.db.models import Q
11                                             - limit_choices_to=Q(nid__gt=10)
12                                             - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
13                                             - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
14         symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
15                                     # 做如下操作时,不同的symmetrical会有不同的可选字段
16                                         models.BB.objects.filter(...)
17 
18                                         # 可选字段有:code, id, m1
19                                             class BB(models.Model):
20 
21                                             code = models.CharField(max_length=12)
22                                             m1 = models.ManyToManyField('self',symmetrical=True)
23 
24                                         # 可选字段有: bb, code, id, m1
25                                             class BB(models.Model):
26 
27                                             code = models.CharField(max_length=12)
28                                             m1 = models.ManyToManyField('self',symmetrical=False)
29 
30         through=None,               # 自定义第三张表时,使用字段用于指定关系表
31         through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
32                                         from django.db import models
33 
34                                         class Person(models.Model):
35                                             name = models.CharField(max_length=50)
36 
37                                         class Group(models.Model):
38                                             name = models.CharField(max_length=128)
39                                             members = models.ManyToManyField(
40                                                 Person,
41                                                 through='Membership',
42                                                 through_fields=('group', 'person'),
43                                             )
44 
45                                         class Membership(models.Model):
46                                             group = models.ForeignKey(Group, on_delete=models.CASCADE)
47                                             person = models.ForeignKey(Person, on_delete=models.CASCADE)
48                                             inviter = models.ForeignKey(
49                                                 Person,
50                                                 on_delete=models.CASCADE,
51                                                 related_name="membership_invites",
52                                             )
53                                             invite_reason = models.CharField(max_length=64)
54         db_constraint=True,         # 是否在数据库中创建外键约束
55         db_table=None,              # 默认创建第三张表时,数据库中表的名称
models.ManyToManyField()函数的主要参数

1、创建多对多表结构:

# 方式一:自定义关系表 (可直接通过类名操作自定义的关系表,且在自定义的关系表中添加任意列名)
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32, db_index=True)
    # 默认为protocol="both",即支持ipv4,也支持ipv协议
    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.SET_NULL)
    application = models.ForeignKey(to='Application', to_field='id', on_delete=models.SET_NULL)

# 方式二:由Django自动创建关系表(通过Django创建的关系表,不可以直接通过类名操作关系表,只能通过间接方式操作表,且Django自动创建表只能默认生成3列数据:id、application_id、host_id)
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32, db_index=True)
    # 默认为protocol="both",即支持ipv4,也支持ipv协议
    ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to="Business", to_field='id', null=True, on_delete=models.SET_NULL)


class Application(models.Model):
    name = models.CharField(max_length=32)
    host = models.ManyToManyField("Host")

# 方式三:既自定义关系表,也有Django ManyToManyField建立的m2m字段,但m2m字段只能进行查询操作,不能进行增删改操作(支持clear),推荐使用方法三
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32, db_index=True)
    # 默认为protocol="both",即支持ipv4,也支持ipv协议
    ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
    port = models.IntegerField()


class Application(models.Model):
    name = models.CharField(max_length=32)
    host = models.ManyToManyField("Host", through="Host", through_fields=["host,""application"])  # through 字段是告诉Django通过哪张表进行m2m关联关系


class HostToApp(models.Model):
    host = models.ForeignKey(to='Host', to_field='nid', on_delete=models.SET_NULL)
    application = models.ForeignKey(to='Application', to_field='id', on_delete=models.SET_NULL)

注:Django自动创建关系表的间接操作方式

 1 # 通过特定条件的表对象进行关系表操作
 2 obj = Application.objects.get(id=1)
 3 # 服务应用的名称
 4 obj.name
 5 
 6 # # 关系表操作
 7 # 在关系表中添加Application、host(单个服务应用、单个主机)对应关系 对应条件:Application表中id=1(服务应用),host表中id=1(主机)
 8 obj.host.add(1)
 9 # 在关系表中添加Application、host(单个服务应用、单个主机)对应关系 对应条件:Application表中id=1(服务应用),host表中id=2(主机)
10 obj.host.add(2)                 
11 # 在关系表中添加Application、host(单个服务应用、多个主机)对应关系 对应条件:Application表中id=1(服务应用),# host表中id=2、id=3、id=4(主机)
12 obj.host.add(2, 3, 4)
13 # 在关系表中添加Application、host(单个服务应用、多个主机列表形式)对应关系 对应条件:Application表中id=1(服务应用),# host表中id=1、id=2、id=3、id=4(主机)
14 obj.host.add(*[1, 2, 3, 4])
15 
16 # 在关系表中移除Application、host(单个服务应用、单个主机)对应关系 对应条件:Application表中id=1(服务应用),host表中id=1(主机)
17 obj.host.remove(1)
18 # 在关系表中移除Application、host(单个服务应用、多个主机)对应关系 对应条件:Application表中id=1(服务应用),host表中id=2、id=4(主机)
19 obj.host.remove(2, 4)
20 # 在关系表中移除Application、host(单个服务应用、多个主机列表形式)对应关系 对应条件:Application表中id=1(服务应用),# host表中id=1、id=2、id=3、id=4(主机)
21 obj.host.remove(*[1, 2, 3])
22 
23 # 在关系表中清除Application、host(单个服务应用、单个/多个主机)对应关系 条件:将关系表中Application id=1(服务应用)对应单个/多个主机关系全部清除
24 obj.host.clear()
25 
26 # set()有些特殊,在关系表中设置对应关系之前,会将之前关系表中,Application id=1(服务应用)所有host(主机)对应关系清除
27 # 在关系表中设置Application、host(单个服务应用、多个主机列表形式)对应关系 对应条件:Application表中id=1(服务应用),# host表中id=1、id=2、id=3(主机)
28 obj.host.set([1, 2, 3])
29 
30 # 所相关的主机对象QuerySet
31 obj.host.all()
关系表的间接操作方式

2、多对多表结构操作示例

在前端页面对app(服务应用)、host(主机)列表进行展示、添加、编辑、删除管理,从而演示一对多表结构的增删查改操作

1、app中的urls.py:

1 from django.conf.urls import url
2 from app1 import views
3 urlpatterns = [
4     url(r'^app$', views.app),
5     url(r'^ajax_add_app$', views.ajax_add_app),
6     url(r'^ajax_submit_edit$', views.ajax_submit_edit),
7     url(r'^ajax_submit_delete$', views.ajax_submit_delete),
8 
9 ]
app中urls.py的路由规则

2、templates:

为了演示方便,没有对host.html进行结构、样式相分离的操作(行为已分离)。

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title></title>
  6     <style>
  7         .host-tag {
  8             display: inline-block;
  9             padding: 3px;
 10             border: 1px solid red;
 11             background-color: palevioletred;
 12         }
 13 
 14         .hide {
 15             display: none;
 16         }
 17 
 18         .shade {
 19             position: fixed;
 20             top: 0;
 21             right: 0;
 22             left: 0;
 23             bottom: 0;
 24             background: black;
 25             opacity: 0.6;
 26             z-index: 100;
 27         }
 28 
 29         .add-modal, .edit-modal {
 30             position: fixed;
 31             height: 300px;
 32             width: 400px;
 33             top: 100px;
 34             left: 50%;
 35             z-index: 101;
 36             border: 1px solid red;
 37             background: white;
 38             margin-left: -200px;
 39         }
 40     </style>
 41 </head>
 42 <body>
 43 
 44 <h1>应用列表</h1>
 45 
 46 <div>
 47     <input id="add_app" type="button" value="添加"/>
 48 </div>
 49 <table border="1">
 50     <thead>
 51     <tr>
 52         <td>应用名称</td>
 53         <td>应用主机列表</td>
 54         <td>操作</td>
 55     </tr>
 56     </thead>
 57     <tbody>
 58     {% for app in app_list %}
 59         <tr aid="{{ app.id }}">
 60             <td>{{ app.name }}</td>
 61             <td>
 62                 {% for host in app.host.all %}
 63                     <span class="host-tag" hid="{{ host.nid }}"> {{ host.hostname }} </span>
 64                 {% endfor %}
 65             </td>
 66             <td>
 67                 <a class="edit">编辑</a>|<a class="delete">删除</a>
 68             </td>
 69         </tr>
 70     {% endfor %}
 71     </tbody>
 72 </table>
 73 
 74 
 75 <div class="shade hide"></div>
 76 <div class="add-modal hide">
 77     <form id="add_form" method="POST" action="/app1/app">
 78         <div class="group">
 79             <input id="app_name" type="text" placeholder="应用名称" name="app_name"/>
 80         </div>
 81         <div class="group">
 82             <select id="host_list" name="host_list" multiple>
 83                 {% for op in host_list %}
 84                     <option value="{{ op.nid }}">{{ op.hostname }}</option>
 85                 {% endfor %}
 86             </select>
 87         </div>
 88 
 89         <input id="add_submit" type="submit" value="提交"/>
 90         <input id="add_submit_ajax" type="button" value="Ajax提交"/>
 91     </form>
 92 
 93 
 94 </div>
 95 
 96 <div class="edit-modal hide">
 97     <form id="edit_form" method="POST" action="/host">
 98         <input type="text" name="nid" style="display:none"/>
 99         <input type="text" placeholder="应用名称" name="app"/>
100         <select name="host_list" multiple>
101             {% for op in host_list %}
102                 <option value="{{ op.nid }}">{{ op.hostname }}</option>
103             {% endfor %}
104         </select>
105         <a id="ajax_submit_edit">确认编辑</a>
106     </form>
107 
108 
109 </div>
110 
111 <script src="/static/jquery-1.12.4.js"></script>
112 <script src="/static/common.js"></script>
113 </body>
114 </html>
app.html

3、static:

在static编写JavaScript公共函数conmon.js(在编写common.js之前需要引入jQuery):

$(function () {
    //打开/关闭模态对话框操作
    $('#add_app').click(function () {
        $('.shade,.add-modal').removeClass('hide');
    });

    $('#cancel').click(function () {
        $('.shade,.add-modal').addClass('hide');
    });
    //添加操作
    $('#add_submit_ajax').click(function () {
        $.ajax({
            url: '/app1/ajax_add_app',
            // data: {'user': 123,'host_list': [1,2,3,4]},
            data: $('#add_form').serialize(),
            type: "POST",
            dataType: 'JSON',   //dataType定义为JSON后,就不用再对服务端返回的数据进行反序列化
            traditional: true,  // traditional定义true后,才能支持data列表形式的value请求参数: {''host_list': [1,2,3,4]}
            success: function (obj) {
                if (obj.status) {
                    $('.shade,.add-modal').addClass('hide');
                    location.reload();
                }
            },
            error: function () {

            }

        })
    });
    //编辑操作
    $('.edit').click(function () {

        $('.edit-modal,.shade').removeClass('hide');

        var hid_list = [];
        $(this).parent().prev().children().each(function () {
            var hid = $(this).attr('hid');
            hid_list.push(hid)
        });
        $('#edit_form').find('select').val(hid_list);
        var aid = $(this).parent().siblings(":first").text();
        $('#edit_form').find('input[name="app"]').val(aid);

        var nid = $(this).parent().parent().attr("aid");
        console.log(nid);
        $('#edit_form').find('input[name="nid"]').val(nid);

        $("#ajax_submit_edit").click(function () {
            $.ajax({
                url: "/app1/ajax_submit_edit",
                type: "POST",
                data: $("#edit_form").serialize(),
                dataType: "JSON",
                success: function (data) {
                    if (data.status) {
                        $('.shade,.edit-modal').addClass('hide');
                        location.reload();
                    }
                }
            })
        });

    });
    //删除操作
    $('.delete').click(function () {
        var hid_list = [];
        $(this).parent().prev().children().each(function () {
            var hid = $(this).attr('hid');
            hid_list.push(hid)
        });
        console.log(hid_list);
        var nid = $(this).parent().parent().attr("aid");
        console.log(nid);
        $.ajax({
            url: "/app1/ajax_submit_delete",
            type: "POST",
            data: {"nid": nid, "host_id_list": hid_list},
            dataType: "JSON",
            traditional: true,
            success: function (data) {
                if (data.status) {
                    location.reload();
                }
            }
        });

    });
})

4、app中的views.py:

import json
from django.shortcuts import redirect
from django.shortcuts import HttpResponse
from django.shortcuts import render
from app1 import models


# form提交数据添加操作
def app(request):
    """
    host函数通过request区别get和post方法,如果是request是get方法,就从数据库中查询数据,然后将查询的数据返回给HTML进行渲染展示
    如果是request是post方法,就从request中提取数据,然后进行数据库添加操作
    :param request:
    :return:
    """
    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 = models.Application.objects.create(name=app_name)
        obj.host.add(*host_list)

        return redirect('/app1/app')


# ajax提交数据添加操作
def ajax_add_app(request):
    ret = {'status': True, 'error': None, 'data': None}
    print(request.POST)
    try:
        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)
    except Exception as e:
            ret['status'] = False
            ret['error'] = "request error"

    return HttpResponse(json.dumps(ret))


# 编辑操作
def ajax_submit_edit(request):
    ret = {'status': True, 'error': None, 'data': None}
    print(request.POST)
    try:
        nid = request.POST.get("nid")
        app_name = request.POST.get("app")
        host_list = request.POST.getlist('host_list')
        print(app_name, host_list)
        obj = models.Application.objects.get(id=nid)
        obj.name = app_name
        obj.save()
        obj.host.set(host_list)
    except Exception as e:
            ret['status'] = False
            ret['error'] = "request error"
    return HttpResponse(json.dumps(ret))


# 删除操作
def ajax_submit_delete(request):
    ret = {'status': True, 'error': None, 'data': None}
    print(request.POST)
    try:
        nid = request.POST.get("nid")
        host_list = request.POST.getlist('host_id_list')
        print(nid, host_list)
        obj = models.Application.objects.get(id=nid)
        obj.host.remove(*host_list)
        models.Application.objects.filter(id=nid).delete()
    except Exception as e:
            ret['status'] = False
            ret['error'] = "request error"
    return HttpResponse(json.dumps(ret))
原文地址:https://www.cnblogs.com/Keep-Ambition/p/8446450.html