(转)Django ====> 实战学习篇六 改造Productlist界面 Django 的输入校验机制 实现输入校验
Django的验证有三层机制:
- 字段类型验证,除了应对数据库字段类型的Field类型外,还有EmailField, FileFIeld, URLField, PhoneNumberField, IPAdressField等等。
- 字段选项验证,如null=true, blank=true,choices editable, unique, unique_for_date等等。
- 表单验证,可以在Form中验证方法,可以针对所有表单做clean验证方法,也可以针对单项的验证方法:clean_xxx。
Product模型中,默认加入了不能为空,要求符合数字验证,还需要如下验证:
1.验证price>0:需要在Form中验证;
2. 验证title唯一:在Model中验证;
3. 验证image_url的扩展名:在Form中验证,还可以顺便在Model中将其改为URLField类型。
实现输入校验:
- 在Model中修改字段参数值,防止重复输入标题,修改字段参数title中unique=True如下:
from django.db import models class Product(models.Model): title = models.CharField(max_length=100,unique=True) description = models.TextField() image_url = models.URLField(max_length=200) price = models.DecimalField(max_digits=8,decimal_places=2)
- 继续修改字段类型,将image_url修改成字段类型URLField:见上边代码
- 限制price和输入的图片地址在form中修改:
depotapp/form.py #/usr/bin/python #coding: utf8 from django import forms from models import * import itertools def anyTrue(predicate, sequence): return True in itertools.imap(predicate, sequence) def endsWith(s, *endings): return anyTrue(s.endswith, endings) class ProductForm(forms.ModelForm): class Meta: model = Product def __init__(self, *args, **kwargs): super(ProductForm, self).__init__(*args, **kwargs) def clean_price(self): price = self.cleaned_data['price'] if price<=0: raise forms.ValidationError("价格必须大于零") return price def clean_image_url(self): url = self.cleaned_data['image_url'] if not endsWith(url, '.jpg', '.png', '.gif'): raise forms.ValidationError('图片格式必须为jpg、png或gif') return url
ProductForm继承自ModelForm,可以根据model属性自动生成表单。
在生成的ProductForm上增加了clean_price和clean_image_url验证。结果如下:
表单的展现如下:
creat_product.html {% extends "base.html" %} {% block title %} 创建产品 {% endblock %} {% block content %} <table> <form action="" method="POST"> {% csrf_token %} {{form}} <tr> <td colspan="2" align="right"><input type="submit" value="Create"/></td> </tr> </form> </table> {% endblock %}
直接输出form对象{{form}}就会将表单格式化,而{%csrf_token%}作用是增加token表单项,避免重复提交。
####改造界面
将设计的内容全部复写到基础模板/depot/templates/base.html和专用模板/depot/templates/depotapp/list_product.html
base.html <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="description" content="a depot implement with Django"/> <meta name="keywords" content="django,depot" /> <meta name="author" content="Holbrook(http://hi.csdn.net/space-2668.html)" /> <title>{% block title %} 标题 {% endblock %}</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> </head> <body> <div class="container"> {% block content %} 内容 {% endblock %} </div> </body> </html> list_product.html {% extends "base.html" %} {% block title %} 产品清单 {% endblock %} {% block content %} <div class="container"> <div class="page-header"> <h2>产品清单</h2> </div> {% for item in list_items.object_list %} <div class="row" style="padding-top:10"> <div class="span3 media-grid"> <a href="#"> <img class="thumbnail" src="{{item.image_url}}" alt=""> </a> </div> <div class="span-two-thirds"> <h4>{{item.title}}</h4> {{item.description}} </div> <div class="span2" style="align:right"> <p><a class="btn primary" href="{% url depotapp.views.view_product item.id %}">查看</a></a> </p> <p><a class="btn success" href="{% url depotapp.views.edit_product item.id %}">编辑</a> </p> <p><a class="btn danger" href="#">删除</a></p> </div> </div> {% endfor %} {% if list_items.has_previous %} <a href="?page={{ list_items.previous_page_number }}">上一页</a> {% endif %} <span class="current"> 第{{ list_items.number }}页,共{{ list_items.paginator.num_pages }}页 </span> {% if list_items.has_next %} <a href="?page={{ list_items.next_page_number }}">下一页</a> {% endif %} <p> <a href="{% url depotapp.views.create_product %}">新增产品</a> </p> {% endblock %} 这个模板继承自base.html 然后两个内容的实现
注意其中链接方式的写法,href="{% url depotapp.views.view_product item.id %}"。这样定义的href是关联到view函数,而不是硬编码的URL。在以后如果改变了URLconf的定义,不需要再更改模板。
最后 填写表单 就可以访问了。
“某度”空间 http://hi.baidu.com/new/wenjiashe521
cnblogs空间 http://www.cnblogs.com/wenjiashe521/