【python】-- Django ORM(進階)

Django ORM(進階)

 上一篇博文簡述了Django ORM的單表操做,在本篇博文中主要簡述Django ORM的連表操做。javascript

 

1、一對多:models.ForeignKey()

應用場景:當一張表中建立一行數據時,有一個單選的下拉框(能夠被重複選擇), 例如:建立用戶信息時候,須要選擇一個用戶類型【普通用戶】【金牌用戶】【鉑金用戶】等html

 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演示

一、建立一對多表結構:前端

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)

 二、一對多表結構操做示例:java

在前端頁面對host列表進行主機展現、添加、編輯、刪除管理,從而演示一對多表結構的增刪查改操做。python

一、app中的urls.py:jquery

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的路由規則

二、templates:ajax

爲了演示方便,沒有對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             width: 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

三、static:django

在static編寫JavaScript公共函數conmon.js(在編寫common.js以前須要引入jQuery):json

$(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();
            }
        }
    });
});

四、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))

  

 

2、多對多: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()函數的主要參數

一、建立多對多表結構:

# 方式一:自定義關係表 (可直接經過類名操做自定義的關係表,且在自定義的關係表中添加任意列名)
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=二、id=三、id=4(主機)
12 obj.host.add(2, 3, 4)
13 # 在關係表中添加Application、host(單個服務應用、多個主機列表形式)對應關係 對應條件:Application表中id=1(服務應用),# host表中id=一、id=二、id=三、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=二、id=4(主機)
19 obj.host.remove(2, 4)
20 # 在關係表中移除Application、host(單個服務應用、多個主機列表形式)對應關係 對應條件:Application表中id=1(服務應用),# host表中id=一、id=二、id=三、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=一、id=二、id=3(主機)
28 obj.host.set([1, 2, 3])
29 
30 # 所相關的主機對象QuerySet
31 obj.host.all()
關係表的間接操做方式

 

二、多對多表結構操做示例

在前端頁面對app(服務應用)、host(主機)列表進行展現、添加、編輯、刪除管理,從而演示一對多表結構的增刪查改操做

一、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的路由規則

二、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

三、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();
                }
            }
        });

    });
})

四、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))
相關文章
相關標籤/搜索