注意点

<form class="form-horizontal" method="post" novalidate>
method="post" : 指定form表单提交方式
novalidate : 去除前端校验
field_obj.widget.attrs['class'] = 'form-control' : 添加class='form-control'属性
<span style="color: red">{{ form_obj.hostname.errors.0 }}</span> # 渲染错误信息 # 如何区分编辑还是新增就是看有没有instance参数
form_obj = ServerModeForm(data=request.POST) # 新增
form_obj = ServerModeForm(instance=edit_obj) # 渲染标签,渲染数据
form_obj = ServerModeForm(data=request.POST,instance=edit_obj) # 编辑 <a href="{% url 'server_edit' server_obj.pk %}">编辑</a>

form.html 添加编辑页面

{% extends 'base.html' %}

{% block content %}
<form class="form-horizontal" method="post" novalidate>
{% csrf_token %}
{% for foo in form_obj %}
<div class="form-group">
<label for="{{ foo.id_for_label }}"
class="col-sm-2 control-label">{{ foo.label }}</label>
<div class="col-sm-10">
{{ foo}}
<span style="color: red">{{ foo.errors.0 }}</span>
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">提交</button>
</div>
</div>
</form>
{% endblock %}

ModelForm

from django.forms import ModelForm
from app01 import models class ServerModeForm(ModelForm):
class Meta:
model = models.Server
fields = "__all__" def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# OrderedDict([('hostname', <django.forms.fields.CharField object at 0x0000029EBC724518>)])
# print(self.fields)
# 给所有的字段加class的属性
for k, field_obj in self.fields.items():
field_obj.widget.attrs['class'] = 'form-control'

添加

html

<a href="{% url 'server_add'%}" class="btn btn-danger" style="margin: 10px 0">添加数据</a>
def server_add(request):
# 1 先生成一个modelform的空对象
form_obj = ServerModeForm() # 渲染标签
if request.method == 'POST':
form_obj = ServerModeForm(data=request.POST) # 新增
# 3 判断是否合法
if form_obj.is_valid():
# 保存数据
form_obj.save()
# 跳转到服务器的展示页
# return redirect('/server/list')
return redirect('server_list') # 还可以写别名 但是如果出现有名无名分组的反响解析 则必须使用reverse方法
# 2 将该对象传给html
return render(request, 'form.html', locals())

编辑

html

{% for server_obj in server_queryset %}
<tr>
<td>{{ server_obj.pk }}</td>
<td>{{ server_obj.hostname }}</td>
<td>
<a href="{% url 'server_edit' server_obj.pk %}">编辑</a>
<a href="" onclick="removeDate(this,{{ server_obj.pk }})" >删除</a>
</td>
</tr>
{% endfor %}

py

def server_edit(request, edit_id):
edit_obj = models.Server.objects.filter(pk=edit_id).first()
# 生成待编辑的modeform对象
form_obj = ServerModeForm(instance=edit_obj) # 渲染标签,渲染数据 if request.method == 'POST':
form_obj = ServerModeForm(data=request.POST, instance=edit_obj) # 编辑
if form_obj.is_valid():
form_obj.save()
return redirect('server_list')
return render(request, 'form.html', locals())

删除

html

{% for server_obj in server_queryset %}
<tr>
<td>{{ server_obj.pk }}</td>
<td>{{ server_obj.hostname }}</td>
<td>
<a href="{% url 'server_edit' server_obj.pk %}">编辑</a>
<a href="" onclick="removeDate(this,{{ server_obj.pk }})" >删除</a>
</td>
</tr>
{% endfor %} # 删除Js
function removeDate(ths,sid) {
var res = confirm('确定删除吗?');
if (res){
$.ajax({
url:'/server/delete/'+sid+'/',
type:'get',
success:function (args) {
if (args.status){
$(ths).parent.parent.remove() # DOM操作,删除标签
}
}
})
}
}

py

def server_delete(request, delete_id):
models.Server.objects.filter(pk=delete_id).delete()
return JsonResponse({'status': True}) # 返回给前端,表示已经删除

代码优化

优化1

将所有的modelform单独抽取出来

将modelform类中所有公共的部分抽取出来形成基类

# 父类
from django.forms import ModelForm class BaseModelForm(ModelForm):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
# print(self.fields) # OrderedDict([('hostname', <django.forms.fields.CharField object at 0x10c99c198>)])
# 给所有的字段加class属性
for k,field_obj in self.fields.items():
field_obj.widget.attrs['class'] = 'form-control' # 子类
from app01.myforms.base import BaseModelForm
from app01 import models class ServerModelForm(BaseModelForm):
class Meta:
model = models.Server
fields = "__all__"

优化2

当模型表字段特别多的时候,并且并不是所有的字段都需要展示到前端给用户观看

from django.forms import ModelForm

class BaseModelForm(ModelForm):
# 自定义字段是否需要加额外属性的配置
exclude_bootstrap = [] def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
# print(self.fields) # OrderedDict([('hostname', <django.forms.fields.CharField object at 0x10c99c198>)])
# 给所有的字段加class属性
for k,field_obj in self.fields.items():
if k in self.exclude_bootstrap:
continue # 排除在外不添加样式
field_obj.widget.attrs['class'] = 'form-control'

优化3

项目表需要额外添加字段

    # 线上服务器地址
path = models.CharField(verbose_name='线上地址',max_length=64)
# 关联服务器
"""
一个项目可以跑在多个服务器上
一个服务器其实也可以跑多个项目 (公司服务器不够的时候 可以混用)
"""
servers = models.ManyToManyField(to='Server',verbose_name='关联服务器') # 项目展示页面额外展示当前两个字段 <th>线上地址</th>
<th>线上关联服务器</th> <td>{{ project_obj.path }}</td>
<td>
{% for server_obj in project_obj.server.all %}
<span style="border: 1px solid black;padding: 5px">{{ server_obj.hostname }}</span>
{% endfor %}
</td>

modelform+代码发布系统前奏的更多相关文章

  1. 【运维工具】Git代码发布系统

    引言 代码发布系统是互联网公司必备的运维系统,作用主要用户发布业务代码 到 业务服务器 为什么需要代码发布系统 有的同学可能说,我们公司服务器就那么一台,做个发布系统太麻烦了? 不认同这说法 发布系统 ...

  2. Walle代码发布系统

    Walle 一个web部署系统工具,配置简单.功能完善.界面流畅.开箱即用!支持git.svn版本管理,支持各种web代码发布,PHP,Python,JAVA等代码的发布.回滚,可以通过web来一键完 ...

  3. svn 结合rsync 的代码发布系统

    由开发提交到测试环境,经测试,在由运维统一上线.试验需求一台测试服务器,一台线上(生产环境)服务器.测试服务器上跑svn是开发用于代码管理,而线上跑的svn是运维用来代码上线的.结合rsync保持测试 ...

  4. walle代码发布系统配置

    walle Walle 一个web部署系统工具,配置简单.功能完善.界面流畅.开箱即用! 支持git.svn版本管理,支持各种web代码发布, PHP,Python,JAVA等代码的发布.回滚,可以通 ...

  5. 【手把手】JavaWeb 入门级项目实战 -- 文章发布系统 (第十二节)

    好的,那么在上一节中呢,评论功能的后台已经写好了,这一节,先把这部分后台代码和前台对接一下. 1.评论功能实现 我们修改一下保存评论按钮的点击事件,用jQuery的方式获取文本框中的值,然后通过aja ...

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统(35)-文章发布系统②-构建项目

    系列目录 注:阅读本文,需要阅读本系列的之前文章 代码生成器下载地址(文章开头处) 接下来我们建立数据库的表和各层的代码 我们只需要两张表,文章列表(MIS_Article)和类别表(MIS_Arti ...

  7. 【NodeJS 学习笔记04】新闻发布系统

    前言 昨天,我们跟着这位大哥的博客(https://github.com/nswbmw/N-blog/wiki/_pages)进行了nodeJS初步的学习,最后也能将数据插入数据库了 但是一味的跟着别 ...

  8. 完成一个MVC+Nhibernate+Jquery-EasyUI信息发布系统

    一.最近学习了Jquery-EasyUI框架,结合之前用过的MVC3+Nhibernate做一个信息发布系统,对工作一年半的自己做一个总结吧!(也正好 供初学者学习!) 二.先上截图(系统简介),让大 ...

  9. 安卓项目-利用Sqlite数据库,开发新闻发布系统

    本教程致力于程序员可以快速的学习安卓移动端手机开发. 适合于已经习得一种编程语言的同仁. 更多志同道合,想要学习更多编程技术的大神们. 小弟不才,麻烦关注一下我的今日头条号-做全栈攻城狮. 本文章是基 ...

随机推荐

  1. str的常用方法

    注:s表示定义的一个字符串变量,如:s = 'hello string' 1.  s.index()  查找元素,若查到则返回该元素索引,含多个该元素则返回第一个,查不到则报错 s = 'hello ...

  2. 利用EPX Studio将C/S程序转成B/S的方法详解(在线模块方式)

    采用 EPX 的在线模块,是最简单的方法,包括实现简单,客户端不需任何设置,客户使用就简单. 1. 设置服务器端参数(EPServer) 1.1 在服务配置工具选项卡中,设置服务项中的名称,路径,激活 ...

  3. C#基础--迭代器初识

    foreach语句是枚举器(enumerator)的消费者,而迭代器(iterator)是枚举器的产生者. 迭代器模式能提供一种顺序访问一个集合内部的元素,而又不会暴露其内部的方法.当然其缺点就是用f ...

  4. Java-用集合存储对象(新手)

    //导入的包.import java.util.ArrayList;//用集合存储对象,遍历集合,取所有元素. 用get方法.//创建的一个类.public class zylx4 { //公共静态的 ...

  5. 推荐三款好用的JSON格式化工具——JSON-handle & HiJson & JSTool

    工具一:JSON-handle JSON-Handle是一款谷歌浏览器插件. 1.访问http://jsonhandle.sinaapp.com/下载 2.打开Chrome浏览器的扩展程序(访问chr ...

  6. go:内置函数 | 闭包 | 数组 | 切片 | 排序 | map | 锁

    内置函数 1.close: 主要是用来关闭channel 2.len:用来求长度,比如string.array.slice.map.channel 3.new与make都是用来分配内存 new用来分配 ...

  7. Mysql性能优化:为什么要用覆盖索引?

    导读 相信读者看过很多MYSQL索引优化的文章,其中有很多优化的方法,比如最佳左前缀,覆盖索引等方法,但是你真正理解为什么要使用最佳左前缀,为什么使用覆盖索引会提升查询的效率吗? 本篇文章将从MYSQ ...

  8. Servlet(三)----Servlet体系与HTTP

    ## Servlet的体系结构 Servlet  ---  接口 | | GenericServlet  ---  抽象类 | | HttpServlet  --  抽象类 GenericServle ...

  9. Redis系列(一):小试牛刀

    引言 随着互联网的高速发展,传统的关系数据库(如MySQL.Microsoft SQL Server等)已不能满足日益增长的业务需求,如商品秒杀.抢购等及时性非常强的功能,随着应用高并发的访问,会造成 ...

  10. jmeter参数化之函数助手(十五)

    jmeter-参数化: 参数化的作用:调用接口入参时.有时要求参数经常变化,如果每次去修改就会变得很繁琐,这时候就需要把经常变化的值改变为提前编辑好的文档或函数中,便于调用时使用不同的值. Jmete ...