先看效果图:

登陆admin后的界面:

查看作者:

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

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

 from django.db import models
from django.utils.html import format_html #把字符串变成html # Create your models here.
class Author(models.Model):
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
email = models.EmailField() def __str__(self):
return "<%s %s>" % (self.first_name,self.last_name) class Meta:
verbose_name_plural = u"作者" class Publisher(models.Model):
name = models.CharField(max_length=64, unique=True)
address = models.CharField(max_length=128,null=True,blank=True)
city = models.CharField(max_length=64)
state_province = models.CharField(max_length=64,help_text="put your province here",verbose_name=u"所属省")
country = models.CharField(max_length=64,editable=False)
website = models.URLField() def __str__(self):
return "<%s>" % (self.name) class Book(models.Model):
name = models.CharField(max_length=128)
authors = models.ManyToManyField(Author) #书多对多到作者
publisher = models.ForeignKey(Publisher) #一对多
publish_date = models.DateField() #精确到天DateField()
status_choices = (("published", u"已出版"),
("producing", u"待出版"),
("forbidden", u"禁书"),
)
# 此时应该给个默认值,给之前没有status字段的书。
status = models.CharField(choices=status_choices, max_length=32, default="producing") def __str__(self):
return "<%s %s>" % (self.name,self.publisher) def colored_status(self):
if self.status == "published":
format_td = format_html("<span style='padding:2px;background-color:yellowgreen'>已出版</span>")
elif self.status == "producing":
format_td = format_html("<span style='padding:2px;background-color:red'>待出版</span>")
elif self.status == "forbidden":
format_td = format_html("<span style='padding:2px;background-color:yellow'>禁书</span>") return format_td colored_status.short_description = "STATUS" #页面显示为colored_status即方法名,这里改名为STATUS

现在你看到我直接贴代码,肯定不爽。好吧……

首先上面有三张表: Author(作者表)、Publisher(出版社表)、Book(图书表)。表与表的关联也很简单,一本书可由多个作者联合出,一个作者可出多本书,书与作者为ManyToMany关系;一本书只能由一个出版社出版,一个出版社可出多本书,一对多,用外键ForeignKey关联。

其它的__str__是啥?verbose_name是毛线东西? 看我之前的博客咯。

你登陆admin后其实是看不到3张表的,需要在admin.py注册一下:

 from app01 import models

 admin.site.register(models.Author)
admin.site.register(models.Book, BookAdmin)
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类(也可以命名为别的~)

 from django import forms
from app01 import models class BookForm(forms.Form):
name = forms.CharField(max_length=10)
# publisher_id = forms.IntegerField(widget=forms.Select)
publish_date = forms.DateField()

第二步: 处理用户请求

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

 def book_form(request):
form = forms.BookForm() # 生成form实例
if request.method == "POST":
print(request.POST)
form = forms.BookForm(request.POST)
if form.is_valid(): #进行验证
print("form is ok")
print(form)
print(form.cleaned_data) #{'name': 'qq', 'publish_date': datetime.date(2017, 3, 14)}
form_data = form.cleaned_data
form_data["publisher_id"] = request.POST.get("publisher_id")
book_obj = models.Book(**form_data) #form_data为字典形式
book_obj.save()
else:
print(form.errors)
publisher_list = models.Publisher.objects.all() return render(request, "app01/book_form.html", {"book_form":form,
"publishers":publisher_list})

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

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">{% csrf_token %}
{{ book_form }}
<select name="publisher_id">
{% for publisher in publishers %}
<option value="{{ publisher.id }}">{{ publisher.name }}</option>
{% endfor %}
</select>
<input type="submit" value="创建图书"/>
</form>
</body>
</html>

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

当你输入书名等信息,再点创建图书时,此时是以POST方式发起请求。

我们要将数据发给django强大的form表单进行验证(你可能没有输入或者日期输入为SB), 这些属于前端的验证,前端的验证是为了减轻后台服务器的压力。只需将请求的数据request.POST传给forms.py的BookForm()即可。

form = forms.BookForm(request.POST)

此时我们还需要进行后台验证,有可能成功,also可能失败。当验证成功时,form.is_valid返回true.

if form.is_valid():   #进行验证

验证成功后,自然是获取数据,存到数据库创建图书啦。好,信息是封装在form实例的,现打印form:

Print(form)

<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" maxlength="10" name="name" type="text"
value="zcl_papa" required /></td></tr>
<tr><th><label for="id_publish_date">Publish date:</label></th><td><input id="id_publish_date" name="publish_
date" type="text" value="2017-03-14" required /></td></tr>

擦,一堆html

要获取干净的数据,需处理一下:

form_data = form.cleaned_data
 Print(form.cleaned_data)

 {'name': 'zcl_papa', 'publish_date': datetime.date(2017, 3, 14)}

form表单定制ending.

这里有个问题,为啥要在BookForm去掉publisher_id字段??

因为无法直接获取出版社的信息(下拉列表为空的),要想在前端界面有供选择出版社的input标签,需要自己在html添加

         <select name="publisher_id">
{% for publisher in publishers %}
<option value="{{ publisher.id }}">{{ publisher.name }}</option>
{% endfor %}
</select>

最后还需要将获得的信息加到字典(干净的数据)中,再添加到数据库。
呵呵,这比较麻烦,下面介绍更优化的方法。

modelform

为了解决前面无法获取publisher_id的问题,引入modelform

modelform与form有很多相似之处的。接下来用modelform做个前端表单,当然,会丑点……

第一步:

在forms.py创建类,继承forms.ModelForm:

可绑定Book表,Book表有什么字段,form表单就有什么字段,当然你也可以用fields使想显示的字段显示在界面。

 class BookModelForm(forms.ModelForm):

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

第二步: 处理用户请求

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

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

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.form-control{
color: red;
}
</style>
</head>
<body>
<form action="" method="post">{% csrf_token %}
{{ book_form }}
<input type="submit" value="创建新书"/>
</form> </body>
</html>

效果图:

app01/forms.py

 from django import forms
from app01 import models class BookForm(forms.Form):
name = forms.CharField(max_length=10)
# publisher_id = forms.IntegerField(widget=forms.Select)
publish_date = forms.DateField() class BookModelForm(forms.ModelForm): class Meta:
model = models.Book #绑定Book类
#fields = {"name", "publish_date"} #只包括name,publish-date字段
exclude = () #代表所有字段都包括
widgets = {
# 可以定义css样式,牛逼啊
"name": forms.TextInput(attrs={"class":"form-control"}),
}

二、admin定制

费话不多说,先上效果图:

第一次看到这界面效果,卧槽,amazing....

django的admin后台可以定制成上面的形式,当然你也可以自己定制得更漂亮。

在admin.py加上一个继承admin.ModelAdmin的类

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

定制后完,需将类当作参数传给admin:

admin.site.register(models.Book, BookAdmin)

定制作者与出版社的效果图:

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

首先你要给book表加上一个新的字段:

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

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

如何实现上图的颜色呢??

在models.py下的Book类(用于创建Book表),定义colored_status方法(也可定义为别的名~) 加入下面代码:

     def colored_status(self):
if self.status == "published":
format_td = format_html("<span style='padding:2px;background-color:yellowgreen'>已出版</span>")
elif self.status == "producing":
format_td = format_html("<span style='padding:2px;background-color:red'>待出版</span>")
elif self.status == "forbidden":
format_td = format_html("<span style='padding:2px;background-color:yellow'>禁书</span>") return format_td colored_status.short_description = "STATUS" #页面默认显示为colored_status即方法名,这里改名为STATUS

自我感觉注释得挺明白的。对不同的status判断,并返回不同的css样式。

这里注意导入format_html,可将字符串变成对应html

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句代码:

 def make_forbidden(modelAdmin, request, queryset):  #queryset:选中的集合;modelAdmin代表BookAdmin类,相当于self
print("----->", modelAdmin,request,queryset)
queryset.update(status="forbidden") #更改选中的为禁书
#使action框有选项set to forbidden
make_forbidden.short_description = "Set to forbidden"

第二步: 在之前定义的BookAdmin类加上actions=[xx], xx为第一步定义的方法名make_forbidden.

class BookAdmin(admin.ModelAdmin):   #在类中加入下面一句代码.
actions=[make_forbidden]

admin.py

 from django.contrib import admin

 # Register your models here.
from app01 import models def make_forbidden(modelAdmin, request, queryset): #queryset:选中的集合;modelAdmin代表BookAdmin类,相当于self
print("----->", modelAdmin,request,queryset)
queryset.update(status="forbidden") #更改选中的为禁书
#使action框有选项set to forbidden
make_forbidden.short_description = "Set to forbidden" class BookAdmin(admin.ModelAdmin): #定制book,需将类当作参数传给admin
# list_display不能显示多对多的,比如authors:
# (admin.E109) The value of 'list_display[2]' must not be a ManyToManyField.
list_display = ("id","name", "publisher","publish_date","colored_status","status") #定制为三列 search_fields = ("name", "publisher__name") #__表示出版社关联到名字
list_filter = ("publisher", "publish_date") #过滤
list_editable = ("name", "publish_date") #可修改
list_per_page = 10 #每页显示数量
#即便只有一个值也要加逗号,不然就不当成元组了
#The value of 'filter_horizontal' must be a list or tuple.
filter_horizontal = ("authors",) #选择作者时进行定制 PS:用于多对多关联
raw_id_fields = ("publisher",) #选择出版社时进行定制 PS:用于FK外键关联 actions = [make_forbidden] admin.site.register(models.Author)
admin.site.register(models.Book, BookAdmin)
admin.site.register(models.Publisher)

可别小看admin action, 比如你可以批量选中很多主机,点击action发送指令,发送文件  and so on. 强!!!

转发注明出处: http://www.cnblogs.com/0zcl/p/6580279.html 

django进阶-modelform&admin action的更多相关文章

  1. 自定义django model form、admin action

    https://www.cnblogs.com/0zcl/archive/2017/03/22/6580279.html 先看效果图: 登陆admin后的界面: 查看作者: 当然你也可以定制admin ...

  2. Django Form and Modelform Admin定义 高级查询)

    Django的form表单一般具有两种功能 1. 验证输入 2.输入HTML ---------模板----------- from django import forms class BookFor ...

  3. Django进阶Admin篇 - admin基本配置

    django admin 是django自带的一个后台app,提供了后台的管理功能. 基础知识点: 一.认识ModelAdmin 管理界面的定制类,如需扩展特定的model界面,需要从该类继承 二.注 ...

  4. django进阶-3

    先看效果图: 登陆admin后的界面: 查看作者: 当然你也可以定制admin, 使界面更牛逼 数据库表结构: app01/models.py from django.db import models ...

  5. 02:Django进阶篇

    目录:Django其他篇 01:Django基础篇 02:Django进阶篇 03:Django数据库操作--->Model 04: Form 验证用户数据 & 生成html 05:Mo ...

  6. Django进阶(一)

    Url进阶 mysit/mysit/urls.py from django.conf.urls import url from django.contrib import admin urlpatte ...

  7. Python之路【第十七篇】Django进阶篇

    规范 确立规范的好处: 代码可读性高 方便代码的定位极其查找 为以后代码扩容带来便利 场景: 在多个APP的场景下,单个app的URL函数功能较多的时候,我们可以通过以下方法来解决. 把Views写成 ...

  8. Django进阶篇(一)

    Form django中的Form一般有两种功能: 1.输入html 2.验证用户输入 最简易的form验证: <!DOCTYPE html> <html lang="en ...

  9. django进阶补充

    前言: 这篇博客对上篇博客django进阶作下补充. 一.效果图 前端界面较简单(丑),有两个功能: 从数据库中取出书名 eg: 新书A 在form表单输入书名,选择出版社,选择作者(多选),输入完毕 ...

随机推荐

  1. Maven是什么?

    Maven是一个项目管理和综合工具.Maven提供了开发人员构建一个完整的生命周期框架.开发团队可以自动完成项目的基础工具建设,Maven使用标准的目录结构和默认构建生命周期. 在多个开发团队环境时, ...

  2. MySQL5.6主从复制搭建基于日志(binlog)

    什么是MySQL主从复制 简单来说,就是保证主SQL(Master)和从SQL(Slave)的数据是一致性的,向Master插入数据后,Slave会自动从Master把修改的数据同步过来(有一定的延迟 ...

  3. Git的杀手级功能之 一 远程仓库

    Git的杀手级功能之一:远程仓库 Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上. 一.注册GitHub账号,然后和本地Git仓库来关联免费获得Git远程仓库来学校git的远程仓 ...

  4. Java基础--深克隆补充

    深克隆文章很多,这里推荐Java提高篇--对象克隆(复制). 以上文章条理清晰,一目了然,但最近在项目中碰到的实际问题是,所要克隆的对象是加上子类父类共计207个,无论用上述两种方式的哪一种,都要一一 ...

  5. 启动zookeeper时出现的问题

    zkEnv.cmd @echo off REM Licensed to the Apache Software Foundation (ASF) under one or more REM contr ...

  6. 决策树之Cart算法一

    Contents    1. CART算法的认识    2. CART算法的原理    3. CART算法的实现 1. CART算法的认识 Classification And Regression ...

  7. jquery获取data-xxx自定义属性的值遇到的问题

    直接用jquery的 data("name") 获取 data-name的值有问题,获取的只是最初的值,即使后边改变也不会变,所以还是要用attr("data-name& ...

  8. 用FileExplorer查看android手机中的数据库

    想查看一下手机中的通讯录数据库,google之后找到了办法. 参考: http://stackoverflow.com/questions/4867379/android-eclipse-ddms-c ...

  9. linux shell搜索某个字符串,然后在后面加上字符串?字符串后面插入字符串?sed字符串后面插入字符串?

    需求描述: 今天在配置nrpe.cfg这个文件,里面有allowed_hosts的IP地址,需要加上监控主机的地址,所以首先要搜索 到这个地址,然后呢,加上监控主机的地址,考虑通过sed命令来实现 操 ...

  10. 配置ORACLE 11g绿色版客户端和PLSQL远程连接环境

    配置ORACLE 11g绿色版客户端和PLSQL环境   本方法是通过使用ORACLE官方提供的精简版客户端,即绿色免安装的客户端.   Instant client的版本很多:主要是Basic和Ba ...