自定义django model form、admin action
https://www.cnblogs.com/0zcl/archive/2017/03/22/6580279.html
先看效果图:
登陆admin后的界面:

查看作者:

当然你也可以定制admin, 使界面更牛逼

数据库表结构: app01/models.py

1 from django.db import models
2 from django.utils.html import format_html #把字符串变成html
3
4 # Create your models here.
5 class Author(models.Model):
6 first_name = models.CharField(max_length=32)
7 last_name = models.CharField(max_length=32)
8 email = models.EmailField()
9
10 def __str__(self):
11 return "<%s %s>" % (self.first_name,self.last_name)
12
13 class Meta:
14 verbose_name_plural = u"作者"
15
16 class Publisher(models.Model):
17 name = models.CharField(max_length=64, unique=True)
18 address = models.CharField(max_length=128,null=True,blank=True)
19 city = models.CharField(max_length=64)
20 state_province = models.CharField(max_length=64,help_text="put your province here",verbose_name=u"所属省")
21 country = models.CharField(max_length=64,editable=False)
22 website = models.URLField()
23
24 def __str__(self):
25 return "<%s>" % (self.name)
26
27 class Book(models.Model):
28 name = models.CharField(max_length=128)
29 authors = models.ManyToManyField(Author) #书多对多到作者
30 publisher = models.ForeignKey(Publisher) #一对多
31 publish_date = models.DateField() #精确到天DateField()
32 status_choices = (("published", u"已出版"),
33 ("producing", u"待出版"),
34 ("forbidden", u"禁书"),
35 )
36 # 此时应该给个默认值,给之前没有status字段的书。
37 status = models.CharField(choices=status_choices, max_length=32, default="producing")
38
39 def __str__(self):
40 return "<%s %s>" % (self.name,self.publisher)
41
42
43 def colored_status(self):
44 if self.status == "published":
45 format_td = format_html("<span style='padding:2px;已出版</span>")
46 elif self.status == "producing":
47 format_td = format_html("<span style='padding:2px;待出版</span>")
48 elif self.status == "forbidden":
49 format_td = format_html("<span style='padding:2px;禁书</span>")
50
51 return format_td
52
53 colored_status.short_description = "STATUS" #页面显示为colored_status即方法名,这里改名为STATUS

现在你看到我直接贴代码,肯定不爽。好吧……
首先上面有三张表: Author(作者表)、Publisher(出版社表)、Book(图书表)。表与表的关联也很简单,一本书可由多个作者联合出,一个作者可出多本书,书与作者为ManyToMany关系;一本书只能由一个出版社出版,一个出版社可出多本书,一对多,用外键ForeignKey关联。
其它的__str__是啥?verbose_name是毛线东西? 看我之前的博客咯。
你登陆admin后其实是看不到3张表的,需要在admin.py注册一下:
1 from app01 import models
2
3 admin.site.register(models.Author)
4 admin.site.register(models.Book, BookAdmin)
5 admin.site.register(models.Publisher)
注册后再刷新页面,便可以看见表了。
一、form表单定制
在django进阶-1已经有下面这张图了,当你输入为空时,django会出现下面的error提示。

但现在你前端玩得很6,你觉得django自己的form表单so uglily,你想自己做个form表单(可用bootstrap美化),但又希望你做的表单有django的验证功能(重要!!)。so, How to do it?? 下面来自定制创建图书的form表单。
第一步: 创建form类

你定制的form表单可能有很多,应该建一个forms.py文件来存放定制的表单。
接下来在forms.py导入forms, 创建BookForm类(也可以命名为别的~)

1 from django import forms
2 from app01 import models
3
4 class BookForm(forms.Form):
5 name = forms.CharField(max_length=10)
6 # publisher_id = forms.IntegerField(widget=forms.Select)
7 publish_date = forms.DateField()

第二步: 处理用户请求
用户最开始请求数据是GET方式, 当输入数据后修改数据(创建图书),提交方式为POST

1 def book_form(request):
2 form = forms.BookForm() # 生成form实例
3 if request.method == "POST":
4 print(request.POST)
5 form = forms.BookForm(request.POST)
6 if form.is_valid(): #进行验证
7 print("form is ok")
8 print(form)
9 print(form.cleaned_data) #{'name': 'qq', 'publish_date': datetime.date(2017, 3, 14)}
10 form_data = form.cleaned_data
11 form_data["publisher_id"] = request.POST.get("publisher_id")
12 book_obj = models.Book(**form_data) #form_data为字典形式
13 book_obj.save()
14 else:
15 print(form.errors)
16 publisher_list = models.Publisher.objects.all()
17
18
19 return render(request, "app01/book_form.html", {"book_form":form,
20 "publishers":publisher_list})

当用户发起GET请求时,要生成一个空的form实例,并从数据库中查找所有的出版社publisher_list,之后进行渲染render. 接下来当然得写book_form.html啦。

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 </head>
7 <body>
8 <form action="" method="POST">{% csrf_token %}
9 {{ book_form }}
10 <select name="publisher_id">
11 {% for publisher in publishers %}
12 <option value="{{ publisher.id }}">{{ publisher.name }}</option>
13 {% endfor %}
14 </select>
15 <input type="submit" value="创建图书"/>
16 </form>
17 </body>
18 </html>

要是上面看不懂了,就别往下看了……可以看下我之前的博客哈。根据上面的html,会出现如下界面:

当你输入书名等信息,再点创建图书时,此时是以POST方式发起请求。
我们要将数据发给django强大的form表单进行验证(你可能没有输入或者日期输入为SB), 这些属于前端的验证,前端的验证是为了减轻后台服务器的压力。只需将请求的数据request.POST传给forms.py的BookForm()即可。
|
1
|
form = forms.BookForm(request.POST) |
此时我们还需要进行后台验证,有可能成功,also可能失败。当验证成功时,form.is_valid返回true.
|
1
|
if form.is_valid(): #进行验证 |
验证成功后,自然是获取数据,存到数据库创建图书啦。好,信息是封装在form实例的,现打印form:
擦,一堆html
要获取干净的数据,需处理一下:
|
1
|
form_data = form.cleaned_data |
form表单定制ending.
这里有个问题,为啥要在BookForm去掉publisher_id字段??
因为无法直接获取出版社的信息(下拉列表为空的),要想在前端界面有供选择出版社的input标签,需要自己在html添加
最后还需要将获得的信息加到字典(干净的数据)中,再添加到数据库。
呵呵,这比较麻烦,下面介绍更优化的方法。
modelform
为了解决前面无法获取publisher_id的问题,引入modelform
modelform与form有很多相似之处的。接下来用modelform做个前端表单,当然,会丑点……
第一步:
在forms.py创建类,继承forms.ModelForm:
可绑定Book表,Book表有什么字段,form表单就有什么字段,当然你也可以用fields使想显示的字段显示在界面。

1 class BookModelForm(forms.ModelForm):
2
3 class Meta:
4 model = models.Book #绑定Book类
5 #fields = {"name", "publish_date"} #只包括name,publish-date字段
6 exclude = () #代表所有字段都包括
7 widgets = {
8 # 可以定义css样式,牛逼啊
9 "name": forms.TextInput(attrs={"class":"form-control"}),
10 }

第二步: 处理用户请求

1 def book_modelform(request):
2 form = forms.BookModelForm
3 print(request.POST)
4 if request.method == "POST":
5 form = forms.BookModelForm(request.POST)
6 if form.is_valid(): # 进行验证
7 print("form is ok")
8 print(form)
9 print(form.cleaned_data) # {'name': 'qq', 'publish_date': datetime.date(2017, 3, 14)}
10 form.save()
11
12 return render(request, "app01/book_modelform.html", {"book_form":form})

第三步: 写html模版,book_modelform.html:

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <style>
7 .form-control{
8 color: red;
9 }
10 </style>
11 </head>
12 <body>
13 <form action="" method="post">{% csrf_token %}
14 {{ book_form }}
15 <input type="submit" value="创建新书"/>
16 </form>
17
18 </body>
19 </html>

效果图:

app01/forms.py
二、admin定制
费话不多说,先上效果图:

第一次看到这界面效果,卧槽,amazing....
django的admin后台可以定制成上面的形式,当然你也可以自己定制得更漂亮。
在admin.py加上一个继承admin.ModelAdmin的类

1 class BookAdmin(admin.ModelAdmin): #定制book,需将类当作参数传给admin
2 # list_display不能显示多对多的,比如authors:
3 # (admin.E109) The value of 'list_display[2]' must not be a ManyToManyField.
4 list_display = ("id","name", "publisher","publish_date","colored_status","status") #定制为三列
5
6 search_fields = ("name", "publisher__name") #__表示出版社关联到名字
7 list_filter = ("publisher", "publish_date") #过滤
8 list_editable = ("name", "publish_date") #可修改
9 list_per_page = 10 #每页显示数量
10 #即便只有一个值也要加逗号,不然就不当成元组了
11 #The value of 'filter_horizontal' must be a list or tuple.
12 filter_horizontal = ("authors",) #选择作者时进行定制 PS:用于多对多关联
13 raw_id_fields = ("publisher",) #选择出版社时进行定制 PS:用于FK外键关联
14
15 actions = [make_forbidden]

定制后完,需将类当作参数传给admin:
|
1
|
admin.site.register(models.Book, BookAdmin) |
定制作者与出版社的效果图:

ok, 现在有个新需求,想在book界面有个可以选择书出版或未出版的功能,如何实现呢? 而且可以给界面的已出版/未出版加上颜色样式??
首先你要给book表加上一个新的字段:

1 status_choices = (("published", u"已出版"),
2 ("producing", u"待出版"),
3 ("forbidden", u"禁书"),
4 )
5 # 此时应该给个默认值,给之前没有status字段的书。
6 status = models.CharField(choices=status_choices, max_length=32, default="producing")
7
8 def __str__(self):
9 return "<%s %s>" % (self.name,self.publisher)

再将status字段加到list_display,就能显示在界面上了。so easy.

如何实现上图的颜色呢??
在models.py下的Book类(用于创建Book表),定义colored_status方法(也可定义为别的名~) 加入下面代码:

1 def colored_status(self):
2 if self.status == "published":
3 format_td = format_html("<span style='padding:2px;已出版</span>")
4 elif self.status == "producing":
5 format_td = format_html("<span style='padding:2px;待出版</span>")
6 elif self.status == "forbidden":
7 format_td = format_html("<span style='padding:2px;禁书</span>")
8
9 return format_td
10
11 colored_status.short_description = "STATUS" #页面默认显示为colored_status即方法名,这里改名为STATUS

自我感觉注释得挺明白的。对不同的status判断,并返回不同的css样式。
这里注意导入format_html,可将字符串变成对应html
|
1
|
from django.utils.html import format_html #把字符串变成html |
admin action
需求又来了……
批量修改书的status,如将选中所有的书全都修改为禁书。

上图的Action下拉框默认只有Delete selected books,如何才能使下拉框能Set to forbidden选项?? 实现选择forbidden再点击Go,便可将选中的书的status改为禁书。
第一步: 在admin.py定义如下方法,方法名你随意。
要使界面下拉框有Set to forbidden选项,可用第5句代码:
1 def make_forbidden(modelAdmin, request, queryset): #queryset:选中的集合;modelAdmin代表BookAdmin类,相当于self
2 print("----->", modelAdmin,request,queryset)
3 queryset.update(status="forbidden") #更改选中的为禁书
4 #使action框有选项set to forbidden
5 make_forbidden.short_description = "Set to forbidden"
第二步: 在之前定义的BookAdmin类加上actions=[xx], xx为第一步定义的方法名make_forbidden.
|
1
2
|
class BookAdmin(admin.ModelAdmin): #在类中加入下面一句代码. actions=[make_forbidden] |
admin.py
可别小看admin action, 比如你可以批量选中很多主机,点击action发送指令,发送文件 and so on. 强!!!
自定义django model form、admin action的更多相关文章
- Django Model Form
ModelForm ModelForm结合了Form和Model,将models的field类型映射成forms的field类型,复用了Model和Model验证, 写更少的代码,并且还实现了存储数据 ...
- django model form 保存方法 django-rest-framework save 修改某一项值 方法
django Model Form django-rest-framework save 方法 修改某个数据的值
- django进阶-modelform&admin action
先看效果图: 登陆admin后的界面: 查看作者: 当然你也可以定制admin, 使界面更牛逼 数据库表结构: app01/models.py from django.db import models ...
- 自定义django的admin后台action
django的admin后台管理系统中自带了一个批量删除所选对象的action. 我们还可以添加自定义的action来实现其它类似的功能,如批量修改某个字段的功能.简单的,例如将文章批量标记为已发布的 ...
- Day19 Django之Form表单验证、CSRF、Cookie、Session和Model操作
一.Form表单验证 用于做用户提交数据的验证1.自定义规则 a.自定义规则(类,字段名==html中的name值)b.数据提交-规则进行匹配代码如下: """day19 ...
- 自定义 Django的User Model,扩展 AbstractUser类注意事项
本篇主要讨论一下User Model的使用技巧. 注意, 由于Django 1.5之后user model带来了很大的变化, 本篇内容只针对django 1.5之后的版本. 1. 确定 User Mo ...
- 自定义django admin及其界面
1.在项目目录下新创建一个app,命名为kingadmin,在templates目录下新建kingadmin目录,用来存放相关页面的模板文件,新建一个templatetags目录,用来存放处理前端模板 ...
- Django 的 model form 组件
Django 的 model form 组件 Model Form 组件的由来 之前介绍过 Django 的 Form 组件(Django的Form表单)使用方法,Form 组件能够帮我们做三件事: ...
- 14 Django之Form和Model Form组件
一.什么是Form 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用 ...
随机推荐
- 管道pipe与dup结合使用,应用实例
管道的一种常见用法:在父进程创建子进程后向子进程传递参数.例如,一个应用软件有一个主进程和很多个不同子进程. 主进程创建子进程后,在子进程调用exec函数执行一个新程序前,通过管道给即将执行的程序传递 ...
- win10 移动热点自动关闭
解决win10移动热点自动关闭
- PHP:第三章——PHP中表达式函数和匿名函数
<?php header("Content-Type:text/html;charset=utf-8"); //表达式函数和匿名函数 /*$A=function(){ ech ...
- SQL Server 调优系列进阶篇 - 如何维护数据库索引
前言 上一篇我们研究了如何利用索引在数据库里面调优,简要的介绍了索引的原理,更重要的分析了如何选择索引以及索引的利弊项,有兴趣的可以点击查看. 本篇延续上一篇的内容,继续分析索引这块,侧重索引项的日常 ...
- 最全的CSS浏览器兼容问题【FF与IE】
1. Div居中问题 div设置 margin-left, margin-right 为 auto 时已经居中,IE 不行,IE需要设定body居中,首先在父级元素定义text-algin: cent ...
- oracle查询在当前数据库下当前用户拥有的表语句
1.查询表的数目: select count(*) from tabs select count(*) from user_tables 2.查询用户拥有哪些表: select * from tabs ...
- DELPHI 5种运行程序的方法具体应用实例(带参数)
http://www.02t.cn/article/code/102.html https://msdn.microsoft.com/en-us/library/windows/desktop/ms6 ...
- 《Python》 文件操作
一.文件操作基本流程: 1.文件基本操作初识: 打开文件: 文件句柄 = open(‘文件路径’,‘编码方式’,‘打开方式’) 第一种:f = open('d:\'a.txt',encoding='u ...
- Python 编程核心知识体系-文件对象|错误处理(四)
错误处理 文件对象
- DevExpress v18.1新版亮点——WinForms篇(七)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress WinForms v18.1 的新功能,快来下载试用新版本! ...