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. class UserType(models.Model):
  7. name = models.CharField(max_length=32)
  8.  
  9. class User(models.Model):
  10. name = models.CharField(max_length=32)
  11. pwd = models.CharField(max_length=32)
  12. ut = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func))
  13.  
  14. # delete from user where id=1
  15. # delete from UserType where id=1 # 报错
  16.  
  17. # UserType.objects.filter(id=1).delete()
  18.  
  19. # 正向
  20. # v = User.objects.all()
  21. # for item in v:
  22. # item.user
  23. # item.pwd
  24. # item.ut.name
  25. # User.objects.all().values('user','ut__name')
  26.  
  27. # 反向
  28. # v = UserType.objects.all()
  29. # for item in v:
  30. # item.name
  31. # item.id
  32. # item.user_set.all() #user_set是通过对象进行反向查找
  33. # models.UserType.objects.all().values('name','user__pwd') #user_pwd是在values中通过pwd条件进行反向查找
  34.  
  35. ### related_name演示:
  36. #添加related_name参数后
  37. ut = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func),related_name="a")
  38. #通过对象进行反向查找,将会"a"进行替代“表名_set”
  39. item.a.all() #替换item.user_set.all()
  40.  
  41. related_query_name演示:
  42. #添加related_query_name参数后
  43. ut = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func),related_query_name="b")
  44. #对象反向查找,将会"b_set"进行替代“表名_set”,条件反向查询时,将会以“b_字段"代替表名"字段"
  45. item.b_set.all() #替换item.user_set.all()
  46. models.UserType.objects.all().values('name','b__pwd') #替换models.UserType.ob jects.all().values('name','user__pwd')

正向、反向查询、related演示

1、创建一对多表结构:

  1. from django.db import models
  2.  
  3. class Business(models.Model):
  4. caption = models.CharField(max_length=32)
  5. code = models.CharField(max_length=32)
  6.  
  7. class Host(models.Model):
  8. nid = models.AutoField(primary_key=True)
  9. hostname = models.CharField(max_length=32, db_index=True)
  10. # 默认为protocol="both",即支持ipv4,也支持ipv协议
  11. ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
  12. port = models.IntegerField()
  13. # on_delete=models.SET_NULL 意思为:可为空的 ForeignKey ,他引用关联的对象被删除时,该项为空,前提是set null=True
  14. 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. 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="">
  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. </tbody>
  68. </table>
  69.  
  70. <h1>主机列表(字典)</h1>
  71. <table border="">
  72. <thead>
  73. <tr>
  74. <th>主机名</th>
  75. <th>业务线名称</th>
  76. </tr>
  77. </thead>
  78. <tbody>
  79. {% for row in v2 %}
  80. <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
  81. <td>{{ row.hostname }}</td>
  82. <td>{{ row.b__caption }}</td>
  83. </tr>
  84. {% endfor %}
  85.  
  86. </tbody>
  87. </table>
  88. <h1>主机列表(元组)</h1>
  89. <table border="">
  90. <thead>
  91. <tr>
  92. <th>主机名</th>
  93. <th>业务线名称</th>
  94. </tr>
  95. </thead>
  96. <tbody>
  97. {% for row in v3 %}
  98. <tr hid="{{ row.0 }}" bid="{{ row.2 }}">
  99. <td>{{ row.1 }}</td>
  100. <td>{{ row.3 }}</td>
  101. </tr>
  102. {% endfor %}
  103.  
  104. </tbody>
  105. </table>
  106.  
  107. <div class="shade hide"></div>
  108. <div class="add-modal hide">
  109. <form id="add_form" method="POST" action="/app1/host">
  110. <div class="group">
  111. <input id="host" type="text" placeholder="主机名" name="hostname"/>
  112. </div>
  113.  
  114. <div class="group">
  115. <input id="ip" type="text" placeholder="IP" name="ip"/>
  116. </div>
  117.  
  118. <div class="group">
  119. <input id="port" type="text" placeholder="端口" name="port"/>
  120. </div>
  121.  
  122. <div class="group">
  123. <select id="sel" name="b_id">
  124. {% for op in b_list %}
  125. <option value="{{ op.id }}">{{ op.caption }}</option>
  126. {% endfor %}
  127. </select>
  128. </div>
  129.  
  130. <input type="submit" value="提交"/>
  131. <a id="ajax_submit">悄悄提交</a>
  132. <input id="cancel" type="button" value="取消"/>
  133. <span id="erro_msg" style="color: red"></span>
  134. </form>
  135.  
  136. </div>
  137.  
  138. <div class="edit-modal hide">
  139. <form id="edit_form" method="POST" action="app1/host">
  140. <input type="text" name="nid" style="display:none"/>
  141. <input type="text" placeholder="主机名" name="hostname"/>
  142. <input type="text" placeholder="IP" name="ip"/>
  143. <input type="text" placeholder="端口" name="port"/>
  144. <select name="b_id">
  145. {% for op in b_list %}
  146. <option value="{{ op.id }}">{{ op.caption }}</option>
  147. {% endfor %}
  148. </select>
  149. <a id="ajax_submit_edit">确认编辑</a>
  150. </form>
  151. </div>
  152.  
  153. <script src="/static/jquery-1.12.4.js"></script>
  154. <script src="/static/common.js"></script>
  155. </body>
  156. </html>

host.html

3、static:

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

  1. $(function () {
  2.  
  3. //添加操作
  4. $('#add_host').click(function () {
  5. $('.shade,.add-modal').removeClass('hide');
  6. });
  7.  
  8. $('#cancel').click(function () {
  9. $('.shade,.add-modal').addClass('hide');
  10. });
  11.  
  12. $('#ajax_submit').click(function () {
  13. $.ajax({
  14. url: "/app1/test_ajax", //url定义ajax发送请求的URL
  15. type: 'POST', //type定义ajax发送请求的方法类型
  16. // data中则是ajax准备发送服务端的数据
  17. //data: {'hostname': $('#host').val(), 'ip': $('#ip').val(), 'port': $('#port').val(), 'b_id': $('#sel').val()},
  18. data: $('#add_form').serialize(), // 将整个form表单中的参数以字典形式发送给服务端,相比上面的写法,更加便捷
  19. success: function (data) { // 服务端返回数据成功后执行的方法
  20. var obj = JSON.parse(data);
  21. if (obj.status) {
  22. location.reload(); //重新加载当前页面(get形式)
  23. } else {
  24. $('#erro_msg').text(obj.error);
  25. }
  26. }
  27. })
  28. });
  29.  
  30. //编辑操作
  31. $('.edit').click(function () {
  32. $('.shade,.edit-modal').removeClass('hide');
  33.  
  34. var bid = $(this).parent().parent().attr('b_id');
  35. var nid = $(this).parent().parent().attr('h_id');
  36. $('#edit_form').find('select').val(bid);
  37. $('#edit_form').find('input[name="nid"]').val(nid);
  38.  
  39. $("#ajax_submit_edit").click(function () {
  40. $.ajax({
  41. url: "/app1/edit",
  42. type: "POST",
  43. data: $('#edit_form').serialize(),
  44. success: function (data) {
  45. var obj = JSON.parse(data);
  46. if (obj.status) {
  47. $('.shade,.add-modal,.edit-modal').addClass('hide');
  48. location.reload();
  49. } else {
  50. $('#erro_msg').text(obj.error);
  51. }
  52. }
  53. });
  54.  
  55. });
  56. })
  57. });
  58.  
  59. //删除操作
  60. $('.delete').click(function () {
  61. var nid = $(this).parent().parent().attr('h_id');
  62. $.ajax({
  63. url: "/app1/del",
  64. type: "POST",
  65. data: {"nid": nid},
  66. success: function (data) {
  67. var obj = JSON.parse(data);
  68. if (obj.status) {
  69. location.reload();
  70. }
  71. }
  72. });
  73. });

4、app中的views.py:

  1. import json
  2. from django.shortcuts import redirect
  3. from django.shortcuts import HttpResponse
  4. from django.shortcuts import render
  5. from app1 import models
  6.  
  7. def host(request):
  8. """
  9. host函数通过request区别get和post方法,如果是request是get方法,就从数据库中查询数据,然后将查询的数据返回给HTML进行渲染展示
  10. 如果是request是post方法,就从request中提取数据,然后进行数据库添加操作
  11. :param request:
  12. :return:
  13. """
  14. if request.method == "GET":
  15. v1 = models.Host.objects.filter(nid__gt=0)
  16. v2 = models.Host.objects.filter(nid__gt=0).values('nid', 'hostname', 'b_id', 'b__caption')
  17. v3 = models.Host.objects.filter(nid__gt=0).values_list('nid', 'hostname', 'b_id', 'b__caption')
  18.  
  19. b_list = models.Business.objects.all()
  20.  
  21. return render(request, 'host.html', {'v1': v1, 'v2': v2, 'v3': v3, 'b_list': b_list})
  22.  
  23. elif request.method == "POST":
  24.  
  25. h = request.POST.get('hostname')
  26. i = request.POST.get('ip')
  27. p = request.POST.get('port')
  28. b = request.POST.get('b_id')
  29. models.Host.objects.create(hostname=h,
  30. ip=i,
  31. port=p,
  32. b_id=b
  33. )
  34. return redirect('/app1/host')
  35.  
  36. # 通过ajax方式提交数据,服务端提取数据操作后返回的示例:
  37. def test_ajax(request):
  38. ret = {'status': True, 'error': None, 'data': None}
  39. try:
  40. h = request.POST.get('hostname')
  41. i = request.POST.get('ip')
  42. p = request.POST.get('port')
  43. b = request.POST.get('b_id')
  44. if h and len(h) > 5:
  45. models.Host.objects.create(hostname=h,
  46. ip=i,
  47. port=p,
  48. b_id=b)
  49. else:
  50. ret['status'] = False
  51. ret['error'] = "hostname error"
  52. except Exception as e:
  53. ret['status'] = False
  54. ret['error'] = "request error"
  55. return HttpResponse(json.dumps(ret))
  56.  
  57. # 编辑操作
  58. def edit(request):
  59. ret = {'status': True, 'error': None, 'data': None}
  60. print(request.POST, request.method)
  61. try:
  62. nid = request.POST.get('nid')
  63. h = request.POST.get('hostname')
  64. i = request.POST.get('ip')
  65. p = request.POST.get('port')
  66. b = request.POST.get('b_id')
  67. models.Host.objects.filter(nid=nid).update(
  68. hostname=h,
  69. ip=i,
  70. port=p,
  71. b_id=b
  72. )
  73. except Exception as e:
  74. ret['status'] = False
  75. ret['error'] = "hostname error"
  76. return HttpResponse(json.dumps(ret))
  77.  
  78. # 删除操作
  79. def delete(request):
  80. ret = {'status': True, 'error': None, 'data': None}
  81. print(request.POST)
  82. try:
  83. nid = request.POST.get('nid')
  84. models.Host.objects.filter(nid=nid).delete()
  85. except Exception as e:
  86. ret['status'] = False
  87. ret['error'] = "request error"
  88. 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、创建多对多表结构:

  1. # 方式一:自定义关系表 (可直接通过类名操作自定义的关系表,且在自定义的关系表中添加任意列名)
  2. class Host(models.Model):
  3. nid = models.AutoField(primary_key=True)
  4. hostname = models.CharField(max_length=32, db_index=True)
  5. # 默认为protocol="both",即支持ipv4,也支持ipv协议
  6. ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
  7. port = models.IntegerField()
  8.  
  9. class Application(models.Model):
  10. name = models.CharField(max_length=32)
  11.  
  12. class HostToApp(models.Model):
  13. host = models.ForeignKey(to='Host', to_field='nid', on_delete=models.SET_NULL)
  14. application = models.ForeignKey(to='Application', to_field='id', on_delete=models.SET_NULL)
  15.  
  16. # 方式二:由Django自动创建关系表(通过Django创建的关系表,不可以直接通过类名操作关系表,只能通过间接方式操作表,且Django自动创建表只能默认生成3列数据:id、application_id、host_id)
  17. class Host(models.Model):
  18. nid = models.AutoField(primary_key=True)
  19. hostname = models.CharField(max_length=32, db_index=True)
  20. # 默认为protocol="both",即支持ipv4,也支持ipv协议
  21. ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
  22. port = models.IntegerField()
  23. b = models.ForeignKey(to="Business", to_field='id', null=True, on_delete=models.SET_NULL)
  24.  
  25. class Application(models.Model):
  26. name = models.CharField(max_length=32)
  27. host = models.ManyToManyField("Host")
  28.  
  29. # 方式三:既自定义关系表,也有Django ManyToManyField建立的m2m字段,但m2m字段只能进行查询操作,不能进行增删改操作(支持clear),推荐使用方法三
  30. class Host(models.Model):
  31. nid = models.AutoField(primary_key=True)
  32. hostname = models.CharField(max_length=32, db_index=True)
  33. # 默认为protocol="both",即支持ipv4,也支持ipv协议
  34. ip = models.GenericIPAddressField(protocol="ipv4", db_index=True)
  35. port = models.IntegerField()
  36.  
  37. class Application(models.Model):
  38. name = models.CharField(max_length=32)
  39. host = models.ManyToManyField("Host", through="Host", through_fields=["host,""application"]) # through 字段是告诉Django通过哪张表进行m2m关联关系
  40.  
  41. class HostToApp(models.Model):
  42. host = models.ForeignKey(to='Host', to_field='nid', on_delete=models.SET_NULL)
  43. 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. <div class="shade hide"></div>
  75. <div class="add-modal hide">
  76. <form id="add_form" method="POST" action="/app1/app">
  77. <div class="group">
  78. <input id="app_name" type="text" placeholder="应用名称" name="app_name"/>
  79. </div>
  80. <div class="group">
  81. <select id="host_list" name="host_list" multiple>
  82. {% for op in host_list %}
  83. <option value="{{ op.nid }}">{{ op.hostname }}</option>
  84. {% endfor %}
  85. </select>
  86. </div>
  87.  
  88. <input id="add_submit" type="submit" value="提交"/>
  89. <input id="add_submit_ajax" type="button" value="Ajax提交"/>
  90. </form>
  91.  
  92. </div>
  93.  
  94. <div class="edit-modal hide">
  95. <form id="edit_form" method="POST" action="/host">
  96. <input type="text" name="nid" style="display:none"/>
  97. <input type="text" placeholder="应用名称" name="app"/>
  98. <select name="host_list" multiple>
  99. {% for op in host_list %}
  100. <option value="{{ op.nid }}">{{ op.hostname }}</option>
  101. {% endfor %}
  102. </select>
  103. <a id="ajax_submit_edit">确认编辑</a>
  104. </form>
  105.  
  106. </div>
  107.  
  108. <script src="/static/jquery-1.12.4.js"></script>
  109. <script src="/static/common.js"></script>
  110. </body>
  111. </html>

app.html

3、static:

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

  1. $(function () {
  2. //打开/关闭模态对话框操作
  3. $('#add_app').click(function () {
  4. $('.shade,.add-modal').removeClass('hide');
  5. });
  6.  
  7. $('#cancel').click(function () {
  8. $('.shade,.add-modal').addClass('hide');
  9. });
  10. //添加操作
  11. $('#add_submit_ajax').click(function () {
  12. $.ajax({
  13. url: '/app1/ajax_add_app',
  14. // data: {'user': 123,'host_list': [1,2,3,4]},
  15. data: $('#add_form').serialize(),
  16. type: "POST",
  17. dataType: 'JSON', //dataType定义为JSON后,就不用再对服务端返回的数据进行反序列化
  18. traditional: true, // traditional定义true后,才能支持data列表形式的value请求参数: {''host_list': [1,2,3,4]}
  19. success: function (obj) {
  20. if (obj.status) {
  21. $('.shade,.add-modal').addClass('hide');
  22. location.reload();
  23. }
  24. },
  25. error: function () {
  26.  
  27. }
  28.  
  29. })
  30. });
  31. //编辑操作
  32. $('.edit').click(function () {
  33.  
  34. $('.edit-modal,.shade').removeClass('hide');
  35.  
  36. var hid_list = [];
  37. $(this).parent().prev().children().each(function () {
  38. var hid = $(this).attr('hid');
  39. hid_list.push(hid)
  40. });
  41. $('#edit_form').find('select').val(hid_list);
  42. var aid = $(this).parent().siblings(":first").text();
  43. $('#edit_form').find('input[name="app"]').val(aid);
  44.  
  45. var nid = $(this).parent().parent().attr("aid");
  46. console.log(nid);
  47. $('#edit_form').find('input[name="nid"]').val(nid);
  48.  
  49. $("#ajax_submit_edit").click(function () {
  50. $.ajax({
  51. url: "/app1/ajax_submit_edit",
  52. type: "POST",
  53. data: $("#edit_form").serialize(),
  54. dataType: "JSON",
  55. success: function (data) {
  56. if (data.status) {
  57. $('.shade,.edit-modal').addClass('hide');
  58. location.reload();
  59. }
  60. }
  61. })
  62. });
  63.  
  64. });
  65. //删除操作
  66. $('.delete').click(function () {
  67. var hid_list = [];
  68. $(this).parent().prev().children().each(function () {
  69. var hid = $(this).attr('hid');
  70. hid_list.push(hid)
  71. });
  72. console.log(hid_list);
  73. var nid = $(this).parent().parent().attr("aid");
  74. console.log(nid);
  75. $.ajax({
  76. url: "/app1/ajax_submit_delete",
  77. type: "POST",
  78. data: {"nid": nid, "host_id_list": hid_list},
  79. dataType: "JSON",
  80. traditional: true,
  81. success: function (data) {
  82. if (data.status) {
  83. location.reload();
  84. }
  85. }
  86. });
  87.  
  88. });
  89. })

4、app中的views.py:

  1. import json
  2. from django.shortcuts import redirect
  3. from django.shortcuts import HttpResponse
  4. from django.shortcuts import render
  5. from app1 import models
  6.  
  7. # form提交数据添加操作
  8. def app(request):
  9. """
  10. host函数通过request区别get和post方法,如果是request是get方法,就从数据库中查询数据,然后将查询的数据返回给HTML进行渲染展示
  11. 如果是request是post方法,就从request中提取数据,然后进行数据库添加操作
  12. :param request:
  13. :return:
  14. """
  15. if request.method == "GET":
  16. app_list = models.Application.objects.all()
  17. host_list = models.Host.objects.all()
  18. return render(request, 'app.html', {"app_list": app_list, 'host_list': host_list})
  19. elif request.method == "POST":
  20. app_name = request.POST.get('app_name')
  21. host_list = request.POST.getlist('host_list')
  22. print(app_name, host_list)
  23.  
  24. obj = models.Application.objects.create(name=app_name)
  25. obj.host.add(*host_list)
  26.  
  27. return redirect('/app1/app')
  28.  
  29. # ajax提交数据添加操作
  30. def ajax_add_app(request):
  31. ret = {'status': True, 'error': None, 'data': None}
  32. print(request.POST)
  33. try:
  34. app_name = request.POST.get("app_name")
  35. host_list = request.POST.getlist('host_list')
  36. print(app_name, host_list)
  37. obj = models.Application.objects.create(name=app_name)
  38. obj.host.add(*host_list)
  39. except Exception as e:
  40. ret['status'] = False
  41. ret['error'] = "request error"
  42.  
  43. return HttpResponse(json.dumps(ret))
  44.  
  45. # 编辑操作
  46. def ajax_submit_edit(request):
  47. ret = {'status': True, 'error': None, 'data': None}
  48. print(request.POST)
  49. try:
  50. nid = request.POST.get("nid")
  51. app_name = request.POST.get("app")
  52. host_list = request.POST.getlist('host_list')
  53. print(app_name, host_list)
  54. obj = models.Application.objects.get(id=nid)
  55. obj.name = app_name
  56. obj.save()
  57. obj.host.set(host_list)
  58. except Exception as e:
  59. ret['status'] = False
  60. ret['error'] = "request error"
  61. return HttpResponse(json.dumps(ret))
  62.  
  63. # 删除操作
  64. def ajax_submit_delete(request):
  65. ret = {'status': True, 'error': None, 'data': None}
  66. print(request.POST)
  67. try:
  68. nid = request.POST.get("nid")
  69. host_list = request.POST.getlist('host_id_list')
  70. print(nid, host_list)
  71. obj = models.Application.objects.get(id=nid)
  72. obj.host.remove(*host_list)
  73. models.Application.objects.filter(id=nid).delete()
  74. except Exception as e:
  75. ret['status'] = False
  76. ret['error'] = "request error"
  77. return HttpResponse(json.dumps(ret))

【python】-- Django ORM(进阶)的更多相关文章

  1. Django orm进阶查询(聚合、分组、F查询、Q查询)、常见字段、查询优化及事务操作

    Django orm进阶查询(聚合.分组.F查询.Q查询).常见字段.查询优化及事务操作 聚合查询 记住用到关键字aggregate然后还有几个常用的聚合函数就好了 from django.db.mo ...

  2. 9.14.16 Django ORM进阶用法

    2018-9-14 14:26:45 ORM 练习题   : http://www.cnblogs.com/liwenzhou/articles/8337352.html 2018-9-14 21:1 ...

  3. Python - Django - ORM 多对多表结构的三种方式

    多对多的三种方式: ORM 自动创建第三张表 自己创建第三张表, 利用外键分别关联作者和书,关联查询比较麻烦,因为没办法使用 ORM 提供的便利方法 自己创建第三张表,使用 ORM 的 ManyToM ...

  4. Django - ORM - 进阶

    一.多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是 ...

  5. Python - Django - ORM 操作表

    ORM 的对应关系: 类        --->    数据库表对象     --->    数据库行属性     --->    字段 操作数据库表     --->     ...

  6. Python - Django - ORM 查询方法

    models.py: from django.db import models class Human(models.Model): id = models.AutoField(primary_key ...

  7. python django ORM

    1.在models.py中创创建类 # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db imp ...

  8. Python - Django - ORM 实例

    准备工作: 首先创建一个名为 Py_Django 的数据库 新建项目,名为 mysite0 创建完成后需要进行几项配置 mysite0/settings.py 下 首先是 html 文件相关 其次是数 ...

  9. Python Django ORM 字段类型、参数、外键操作

    AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 primary ...

  10. Python Django ORM基本增删改查

    工程下的urls.py中增加如下: from cmdb import views as cmdb #要把你要操作的项目import进来 urlpatterns = [ url(r'orm', cmdb ...

随机推荐

  1. jQuery 获取DOM节点的两种方式

    jQuery中包裹后的DOM对象实际上是一个数组,要获得纯粹的DOM对象可以有两种方式: 1.使用数组索引方式访问,例如: var dom = $(dom)[0]; 如: $("#id&qu ...

  2. SSH——增删改的实现一

    在上一节介绍了关于BOS项目底层的查询操作,接下来介绍一下curd里的其他三项操作步骤 一. 取派员添加 利用easyui在staff.jsp页面里构造添加页面(相关JavaBean创建步骤省略) & ...

  3. 【MyBatis学习01】宏观上把握MyBatis框架

    今天开始学习mybatis框架,博客主要记录学习过程中的一些总结,如有错误之处,欢迎留言指正~先用mybatis的鸟鸟来镇个楼,咳咳~~ mybatis框架是一个持久层框架,是Apache下的顶级项目 ...

  4. Angular2升级到Angular4

    angular4终于在两天前发布了正式版本,那么怎么升级呢?其实angular2和angular4之间属于平滑过渡,并不像1和2之间颠覆性的重写代码. npm uninstall -g @angula ...

  5. ubuntu 12.04上安装emacs24

    1.如果安装了emacs23的先删掉 sudo apt-get purge emacs23 2.默认的软件源中没有emacs24,需要添加新源 sudo add-apt-repository ppa: ...

  6. Perl/C#连接Oracle/SQL Server和简单操作

    连接数据库是一个很常见也很必须的操作.先将我用到的总结一下. 1. Perl 连接数据库 Perl 连接数据库的思路都是: 1)使用DBI模块: 2)创建数据库连接句柄dbh: 3)利用dbh创建语句 ...

  7. spark单机模式

    1.下载spark,解压2.复制conf/spark-env.sh和conf/log4j.properties cp spark-env.sh.template spark-env.sh cp log ...

  8. X264参考手册

    艺搜简介 基本语法: x264 [options]-o outfile infile 注意与ffmpeg的输入输出文件位置恰好相反: ffmpeg[options][[infile options]- ...

  9. AV1视频编码标准资源汇总

    一直不看好HEVC,总觉得这东西绝对不可能再恢复像h264那么辉煌了,如此高昂的授权费,被淘汰估计也就这一两年了,有必要预研一下AV1,马上进去二进制码流冻结流程了,感觉aom越来越近了,毕竟goog ...

  10. JNDI提供了一种统一的方式,可以用在网络上查找和访问服务

    JNDI提供了一种统一的方式,可以用在网络上查找和访问服务.通过指定一个资源名称,该名称对应于数据库或命名服务中的一个记录,同时返回数据库连接建立所必须的信息. JNDI主要有两部分组成:应用程序编程 ...