注意点

<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. 2019计蒜客信息学提高组赛前膜你赛 #2(TooYoung,TooSimple,Sometimes Naive

    计蒜客\(2019CSP\)比赛第二场 巧妙爆零这场比赛(我连背包都不会了\(QWQ\) \(T1\) \(Too\) \(Young\) 大学选课真的是一件很苦恼的事呢! \(Marco\):&qu ...

  2. 033.Kubernetes集群安全-API Server认证及授权

    一 Kubernetes集群安全 1.1 安全机制 Kubernetes通过一系列机制来实现集群的安全控制,其中包括API Server的认证授权.准入控制机制及保护敏感信息的Secret机制等.集群 ...

  3. 【分布式锁】01-使用Redisson实现可重入分布式锁原理

    前言 主流的分布式锁一般有三种实现方式: 数据库乐观锁 基于Redis的分布式锁 基于ZooKeeper的分布式锁 之前我在博客上写过关于mysql和redis实现分布式锁的具体方案:https:// ...

  4. 附014.Kubernetes Prometheus+Grafana+EFK+Kibana+Glusterfs整合解决方案

    一 glusterfs存储集群部署 注意:以下为简略步骤,详情参考<附009.Kubernetes永久存储之GlusterFS独立部署>. 1.1 架构示意 略 1.2 相关规划 主机 I ...

  5. 一文了解服务端推送(含JS代码示例)

    常用的服务端推送技术,包括轮询.长轮询.websocket.server-sent-event(SSE) 传统的HTTP请求是由客户端发送一个request,服务端返回对应response,所以当服务 ...

  6. 小白学 Python 数据分析(18):Matplotlib(三)常用图表(上)

    人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Pandas (一)概述 小白学 Python 数据分析(3):P ...

  7. Shell:sed用法 - 查找并替换字符串

    原文链接 语法 sed 's/serach_str/replace_str/g' file_path 在某个文件中查找所有的serach_str并替换为replace_str 参数 描述 serach ...

  8. 一款带Web面板的轻量级、高性能内网穿透工具:nps使用教程

    说明:内网穿透工具之前已经介绍了不少了,比如Frp.lanproxy.Holer等,现在再介绍个带Web面板的穿透工具nps,之前叫easyProxy,只是改名了而已,该工具是一款使用go语言编写的轻 ...

  9. (数据科学学习手札80)用Python编写小工具下载OSM路网数据

    本文对应脚本已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们平时在数据可视化或空间数据分析的过程中经常会 ...

  10. 文本编辑器之kindeditor

    摘要:最近在自己学习搭建网站的时候,突然要搭建网站的时候发现了一个好东西,那就是kindeditor这个文本编辑器,这个编辑器简单好用,而且很小,并且是开源的. 文本编辑器介绍 KindEditor ...