如何正确使用 django使用 Forms

发表于日 5:19 p.m.& &
是个Django第三方组件,目标是使项目能在数据库中存储层级数据(树形数据)。它主要实现了修改过的前序遍历算法,如果你对原理还不是很了解,可以看我的。当然,使用mptt时,原理是可以不用了解的,因为具体的实现细节都已经隐藏。不过,如果项目不是使用的Django,可以参考具体的实现原理。
在整篇文章中,我们将会拿《》中的例子作为本文的例子。我们打算在数据库中存储这张图中的数据:
在介绍mptt之前,如果你的需求仅仅是像这样显示以上数据:
mptt就显得大材小用了,因为Django已经有内置模板过滤器来完成这个工作:unordered_list()。如果你的需求不只这么简单,那就跳过这一段。不过这里还是要讲解一下unordered_list的做法。我们就来实现以上的结果。
当然我们首先要写一个简单的Model。
from django.db import models
class Food(models.Model):
title = models.CharField(max_length=50)
parent = models.ForeignKey("self", blank=True, null=True, related_name="children")
def __unicode__(self):
return self.title
开启自动admin,在后台添加完数据。接着,我们来看看怎么样使用unordered_list这个过滤器来显示树形图。
按照官方文档的说法,显示时传递给template的数据应该是这样:
['Food', ['Fruit', ['Red', ['Cherry'], 'Yellow', ['Banana']], 'Meat', ['Beef', 'Pork']]]
我们需要写一个递归的工具函数:
def display(foods):
display_list = []
for food in foods:
display_list.append(food.title)
children = food.children.all()
if len(children) & 0:
display_list.append(display(food.children.all()))
return display_list
于是在views中,我们只要得到根节点,然后把disaply函数生成的列表传递给template,就像这样:
from django.shortcuts import render_to_response
def unordered_list(request):
foods = Food.objects.filter(parent=None)
var = display(foods)
return render_to_response('mpttexample/unordered_list.html', {'var': var})
最后在模板中添加:
{{ var|unordered_list }}
就可以看到显示效果了。
关于unordered_list过滤器的用法就介绍到这里。因为有时候需求不止这么简单,比如有时需要展现样式等等,unordered_list就远远不够了。这个时候就需要mptt,下面开始介绍mptt的用法。
首先是安装mptt,如果安装了setup tools,就可以用这个指令:
easy_install django-mptt
下载包安装的方式就不赘述了,下载地址在。
安装完成后,需要在settings文件下的INSTALLED_APPS中添加'mptt'。
接着写Models,这里我们的Models相之前的实现几乎没有任何的变化。只需继承MPTTModel类:
class MPTTFood(MPTTModel):
title = models.CharField(max_length=50)
parent = models.ForeignKey("self", blank=True, null=True, related_name="children")
def __unicode__(self):
return self.title
这里需要说明的是,实际上MPTTModel隐藏了四个变量:level,lft,rght和tree_id。大多数时候我们是用不到这几个变量的。另外,如果你的Model中parent变量名字不是"parent"时,应当在Model类中MPTT元类中指明:
from mptt.models import MPTTModel
class MPTTFood(MPTTModel):
title = models.CharField(max_length=50)
parent_food = models.ForeignKey("self", blank=True, null=True, related_name="children")
class MPTTMeta:
parent_attr = 'parent_food'
def __unicode__(self):
return self.title
Model的其他选项,请参考。
对于继承MPTTModel的类的实例,将会有额外的方法,比如get_ancestors(更多参考)。我们运行manage.py shell命令作实验:
python manage.py shell
如果安装了自动Admin,可以在Admin模板中像这样显示数据:
只需在admin.site注册,像这样:
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
admin.site.register(MPTTFood, MPTTModelAdmin)
接下来的话题,就是怎样在模板中显示的问题。我们来修改之前ordered_list的显示,结构是一样的,只是对于叶子节点,我们让它显示成红色。在模板中,不要忘了加&{% load mptt_tags %}&。
{% load mptt_tags %}
{% recursetree nodes %}
{% if node.is_leaf_node %}
{{ node.title }}
{% else %}
{{ node.title }}
{{ children }}
{% endif %}
{% endrecursetree %}
这里在视图中传递给模板的参数名必须是nodes。views中就像这样:
def mptt(request):
nodes = MPTTFood.tree.all()
return render_to_response('mpttexample/mptt.html', {'nodes': nodes})
模板中的其他用法,请参考。
关于mptt的介绍就到这里,如果以上这些不能满足你的需求,如在django forms中使用mptt form field等等,请继续参考MPTT官方文档。
过段时间,再和大家分享MPTT的源码。
赞这篇文章
给作者留言
残阳似血(),程序猿一枚,把梦想揣进口袋的挨踢工作者。现加入阿里巴巴,研究僧毕业于上海交通大学软件学院ADC实验室。熟悉分布式计算、基于图模型的分布式数据库和并行计算、Dpark/Spark以及Python web开发(Django、tornado)等。
残阳似血的微博
残阳似血(),程序猿一枚,把梦想揣进口袋的挨踢工作者。现加入阿里巴巴,研究僧毕业于上海交通大学软件学院ADC实验室。熟悉分布式计算、基于图模型的分布式数据库和并行计算、Dpark/Spark以及Python web开发(Django、tornado)等。
上海闵行区东川路800号
上海交通大学这是一个延续的这个问题中,我试图找出如何构造一个的纬度/经度FloatFields。我已@西蒙的views和重组我的模型看起来像这样:
class Point(models.Model):
lat = models.FloatField()
lon = models.FloatField()
class Thing(models.Model):
point = models.ForeignKey(Point)
我的表单具有对应于从谷歌地图“经度和纬度坐标值两个字段:
class StepThreeForm(forms.Form):
lat = forms.FloatField()
lon = forms.FloatField()
然而,这并不为工作的原因,但我不知道如何解决它。为了澄清,我想有对应的外键值两个表单栏位lat和lon。这里是(我一个FormWizard和forms.Form):
url(r'^mapform/$', login_required(MyWizard.as_view([StepOneForm, StepTwoForm, StepThreeForm])), name='create'),
class MyWizard(SessionWizardView): ## this view also serves to edit existing objects and provide their instances
def done(self, form_list, **kwargs):
id = form_list[0].cleaned_data['id']
thing = Thing.objects.get(pk=id)
instance = thing
thing = None
instance = None
if thing and thing.user != self.request.user:
raise HttpResponseForbidden()
if not thing:
instance = Thing()
for form in form_list:
for field, value in form.cleaned_data.iteritems():
setattr(instance, field, value)
instance.user = self.request.user
instance.save()
return render_to_response('wizard-done.html', {
'form_data': [form.cleaned_data for form in form_list],})
我明白任何和所有的建议和帮助!
编辑:根据富田雄二的输入更新。其中大部分取得了很大的意义(谢谢!),但我不知道为什么它会导致一个ValueError异常。
class MyWizard(SessionWizardView):
for form in form_list:
form.save(instance)
class StepOneForm(forms.Form):
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
class StepTwoForm(forms.Form):
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
我相信,我应该保持表单域纬度和lon CodeGo.net,我一个谷歌地图在我的表单和采取的纬度和lon从选定的输入,然后从这些值构造一个点字段:
class StepThreeForm(forms.Form):
lat = forms.FloatField()
lon = forms.FloatField()
def save(self, thing):
thing.point = Point.objects.get_or_create(lat=self.cleaned_data.get('lat'), lon=self.cleaned_data.get('lon'))
这将产生一个ValueError: Cannot assign "(&Point: Point object&, False)": "Thing.point" must be a "Point" instance.Traceback:
File "/lib/python2.7/django/core/handlers/base.py" in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/lib/python2.7/django/contrib/auth/decorators.py" in _wrapped_view
return view_func(request, *args, **kwargs)
File "/lib/python2.7/django/views/generic/base.py" in view
return self.dispatch(request, *args, **kwargs)
File "/lib/python2.7/django/contrib/formtools/wizard/views.py" in dispatch
response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "/lib/python2.7/django/views/generic/base.py" in dispatch
return handler(request, *args, **kwargs)
File "/lib/python2.7/django/contrib/formtools/wizard/views.py" in post
return self.render_done(form, **kwargs)
File "/lib/python2.7/django/contrib/formtools/wizard/views.py" in render_done
done_response = self.done(final_form_list, **kwargs)
File "/myproject/myapp/forms.py" in done
form.save(instance)
File "/myproject/myapp/forms.py" in save
thing.point = Thing.objects.get_or_create(lat=self.cleaned_data.get('lat'), lon=self.cleaned_data.get('lon'))
File "/lib/python2.7/django/db/models/fields/related.py" in __set__
self.field.name, self.field.rel.to._meta.object_name))
本文地址 :CodeGo.net/611945/
-------------------------------------------------------------------------------------------------------------------------
1. 我已经建立save方法对每个表单它知道如何将自身保存到数据库中。它遵循一个通用的模式是“的表单通过form.save执行其行动()”,因此它应该是直观的遵循。
底线是,现在你有一个毯子:“每场各种表单,设置属性的东西对这些领域”。
既然在现实中你有每表单保存的行为,我觉得很有道理,要求通过实例给每个窗体,让每个窗体都有机会将数据保存在适当的领域的方式。
class Form1(...):
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
class Form2(...):
def save(self, thing):
thing.point = Point.objects.get_or_create(lat=self.cleaned_data.get('lat'), long=...)
# note, you may not want get_or_create if you don't want to share points.
您的视图会再
for form in form_list:
form.save(instance)
只是一个想法。
如果你想更干吧 CodeGo.net,现在像你其他表单的自动化,我会建立具有已定义的基本表单:
class BaseSaveBehaviorForm(forms.Form):
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
class NormalBehaviorForm(BaseSaveBehaviorForm):
# your forms as usual
class SpecialSaveBehaviorForm(forms.Form):
def save(self, instance):
# do something unusual
本文标题 :Django的:保存外键的表
本文地址 :CodeGo.net/611945/
Copyright (C) 2014 CodeGo.net 沪ICP备号 联&系& c&o&d&e&g&o &@&1&2&6&.&c&o&m跟我一起Django - 06 模板和表单处理
6. 模板和表单处理
1.1 理解Contexts
1.2 模板语言语法
1.2.1 模板过滤器
1.2.2 标签Tag
1.2.3 Blocks和Extends
跳出当前模板和其他模板交互
1.2.4 include
2.1 定义表单
2.1.1 基于模型的表单
2.1.2 保存ModelForm
2.1.3 区别于Model
2.1.4 继承表单
2.2 填写表单
2.3 验证和清理
2.4 显示表单
2.4.1 显示全部表单
2.4.2 逐个显示表单
2.4.3 Widget
2.4.4 重写一个变量的默认widget
Django的模板系统绝不仅仅是用于生成HTML,还有 log文件、Email正文、CSV文件等任何文本格式文件。
1.1 理解Contexts
Django 把传递给一个渲染模板的信息称之为 context, 实质上就是包含键值对的类似字典的 Context对象
准备Contexts有两种方式:
一种是上一篇中用到的,将Contexts作为参数传递
render_to_response(&person/detail.html&, {&person&:person})
直接将数据作为render_to_response的参数传递;
或者在使用通用视图时把extra_context参数加上
& &return object_list(request,
& & & & queryset = Person.objects.filter(last__istartswith=last_name)
第二种方式是通过 context处理器, 这个东东类似中间件,可以定义各种函数,在模板渲染之前来把键值对附加到所有context上去。
这也是认证框架这样的特性,为什么能保证特定的数据在全站范围里都能访问到的原因。
def breadcrumb_processor(request):
& & return {
& & & & 'breadcrumb': request.path.split('/')
通常处理器都放在根目录的 context_processors.py文件中或是app的目录中;
另外还需要在 settings.py中激活才可以使用, 通常是在一个叫做TEMPLATE_CONTEXT_PROCESSORS 的元组中, 类似中间件的激活。
1.2 模板语言语法
跟其他一些非XML的 模板语言如Smarty相比, Django的模板语言没有要保持 XHTML兼容性的意思,
而是用特殊的字符来把(模板变量以及逻辑命令)和静态内容(HTML)分开来。
跟其他模板语言一样,Django模板系统也有 单独命令 和 模块级命令 , 分别是{{ variable }}, {% command %}
下面的例子渲染context内容:{&title_text&:&My WebPage&, &object_list&: [&One&, &Two&, &Three&]}
& & &head&
& & & & &title&{{ title_text }}&/title&
& & &/head&
& & &body&
& & & & &ul&
& & & & {% for item in object_list %}
& & & & & & &li&{{ item }}&/li&
& & & & {% endfor %}
& & & & &/ul&
& & &/body&
陷阱:Django在模板中输出context变量的时候,会隐式调用 unicode方法, 所以对象以及其他非字符串变量会被尽量转换成 Unicode字符串。
如果你要输出没有定义 unicode 方法的对象,在模板里是看不到它们的,因为Python表示对象用的是 & & ,正好在html中啥也不是,故不显示。
&&& print object()
&object object at 0x40448&
1.2.1 模板过滤器
类似 UNIX 管道
string|lower
person.is_avaliable|yesno:&Yes,No&
1.2.2 标签Tag
if, ifequal, for, endfor, block, include, extends ...
{% ifequal object_list|length 10 %}
{% if object_list|lengthis 10 %}
模块级命令如 if for , 可以修改它们的局部 context, 很实用
如 for 提供了 {{ forloop }}局部变量, 用法有 forloop.first .last .counter .counter0
跳出当前模板和其他模板交互
通过模板继承和模板包含来完成代码的组合和重用
继承通过 blocks extends 实现;包含通过 include 实现
1.2.3 Blocks和Extends
{% extends %} 必须在模板的顶部调用,并告知渲染引擎这个模板是从一个更高级的模板继承而来
{% blocks %} 是一个模块级标签,一个模板中可以定义多个block, 预备让那些要扩展它的模板去填充的小节
举个例子,三层网站布局
/section1/
/section2/
/section1/page1/
/section1/page2/
#base.html
&html&&head&&title&{% block title %}My Web Site{% endblock %}&/title&&/head&&/html&
&div id=&content&&{% block content %}{% endblock %}&/div&
section1.html
{% extends &base.html& %}
{% block title %} Section1 {% endblock %}
page1.html
{% extends &section1.html& %}
{% block content %} This Page 1 {% endblock %}
page2.html
{% extends &section1.html& %}
{% block content %} This Page 2 {% endblock %}
1.2.4 include
很简单,类似PHP的include,实现代码重用
/ganiks/p/django-template-and-forms.html
Django提供了 forms 库来把框架里的三个主要的组件联系在一起:
模型里定义的字段
模板里显示的HTML表单标签
验证用户输入和显示错误信息的能力
2.1 定义表单
表单处理的核心类Form 其实跟 Model 看上去是基本相同的, 它们都是处理 变量对象集合, 只是代表的意义不同,一个是Web表单,一个是数据表
有了Form类,我们不光可以轻松处理跟Model模型 100%匹配的表单,还可以隐藏或是省略特定变量,或是把多个model里的变量放在一个表单,或是处理和数据库存储毫无关系的表单, 非常灵活。
from django import newforms as forms
class PersonForm(forms.Form):
& & first = forms.CharField(max_length=100, required=True)
& & last = forms.CharField(max_length=100, required=True)
& & middle = forms.CharField(max_length=100)
2.1.1 基于模型的表单
Django允许你使用Form变形 ModelForm 类为任何 Model类或实例取得一个Form子类,
一个ModelForm和普通Form基本一样,但是包含了一个Meta嵌套类(类似Model里的Meta),内含一个必须的属性 model
下面重新定义下上面的 Form
from django import newforms as forms
from mysite.myapp.models import Person
class PersonForm(forms.ModelForm):
& & class Meta:
& & & & model = Person
完美体现了Django的DRY don't repeat yourself 的原则
2.1.2 保存ModelForm
基于模型创建的表单跟手动生成的表单有一个很重要的区别是, save方法
from mysite.myapp.forms import PersonForm
form = PersonForm({'first':'John', 'last':'Doe'})
new_person = form.save()
你经常会需要在数据,从表单提交后,存储到数据库之前,修改它们;
而最好还是在后一个时间段修改,因为这时候你修改的是Python值,而不是POST数据。
为了能让在save之前修改, save方法提供了一个可选的commit参数(默认是True), 控制你是否真的更新数据库。
from mysite.myapp.forms import PersonForm
form = PersonForm({'first':'John', 'last':'Doe'})
new_person = form.save(commit=False)
new_person.middle = 'Danger'
new_person.save()
如果使用 commit=False 来延迟保存的ModelForm包含了相关对象, Django会给表单(不是Model对象的结果)添加一个额外的方法 save_m2m, 让你正确安排时间的顺序。
form = PersonForm(input_including_related_objects)
new_person = form.save(commit=False)
new_person.middle = 'Danger'
new_person.save()
form.save_m2m()
如果没有最后的 save_m2m(), related objects会出问题的。
2.1.3 区别于Model
继承模型的表单是非常方便,但是有时候我们需要排除一些变量,并不是需要所有的变量,不需要重新写一个Form子类出来,有好几种方法:
from django import newforms as forms
from mysite.myapp.models import Person
class PersonForm(forms.ModelForm):
& & class Meta:
& & & & model = Person
& & & & exclude = ('middle', )
class PersonForm(forms.ModelForm):
& & class Meta:
& & & & model = Person
& & & & fields = ('first', 'last')
这样一来,忽略的变量就不会被save方法保存,所以忽略它时要确保DB中的定义是 null=True的,否则会报错。
有时候,还需要重写forms层里的Field子类,验证和显示特定的变量,如下重新定义了first字段的长度
class PersonForm(forms.ModelForm):
& & &first = forms.CharField(max_length=10)
& & &class Meta:
& & & & &model = Person
关于&关系表单变量& relationship form fields
ModelChoiceField -- ForeignKey
ModelMultipleChoiceField -- ManyToManyField
还记得吗?当时Model定义外键和多对多关系的时候,使用了 limit_choices_to参数, 其实等效的方法可以在表单层变量里自定义一个 queryset 参数, 用来接收一个 特定的 QuerySet 对象, 如下例子Person模型有一个指向其他Person对象的没有限制的父ForeignKey:
class PersonForm(forms.ModelForm):
& & class Meta:
& & & & model = Person
class SmithChildForm(forms.ModelForm):
& & parent = forms.ModelChoiceField(queryset=Person.objects.filter(last='Smith'))
& & class = Meta:
& & & & model = Person
2.1.4 继承表单
跟继承模型一样
from django import newforms as forms
class PersonForm(forms.Form):
& & first = forms.CharField()
& & last = forms.CharField()
class Person2Form(forms.Form):
& & first = forms.CharField()
& & last = forms.CharField()
class AgedPersonForm(PersonForm):
& & age = forms.IntergerField()
class MixedPerson(PersonForm, PersonForm2):
& & # mixed extends
2.2 填写表单
Django的表单库中有2种表单
绑定的 bound, 和数据有关系
没绑定的 unbound, 没有数据
表单有一个特性, 可以随便往表单的数据字典里添加额外的键值对, 表单会自动无视那些和它们定义无关的输入
from mysite.myapp.forms import PersonForm
def process_form(request):
& & post = request.POST.copy()
& & form = PersonForm(post)
还可以创建一个虽然未绑定,但是模板打印时载入显示了初始值的表单, 这个命名构造函数参数 initial 是一个字典
每个表单变量也都有一个类似的参数,允许指定它自己的默认值,不过如果有冲突的话, 表单级的 initial 会覆盖变量级的
from django import newforms as forms
from django.shotcuts import render_to_response
class PersonForm(forms.Form):
& & first = forms.CharField()
& & last = forms.CharField(initial='Smith')#表单定义时,变量级initial参数
& & middle = forms.CharField()
def process_form(request):
& & if not reuqest.POST:
& & & & form = PersonForm(initial={'first':'John'}) #创建表单实例时, 表单级initial参数,这里如果也定义了last, 则会覆盖上面的Smith
& & & & return render_to_response('myapp/form.', {'form':form})
使用实例层initial参数的好处在于它的值可以在表单创建的时候才被构造出来, 这样一来,你可以引用在表单或是模型定义的时候还不知道的信息,特别是请求对象里的信息,看下面的例子
from django.shotcuts import get_object_or_404, render_to_response
from mysite.myapp.models import Person, PersonForm
# Views's URL /person/&id&/children/add
def add_relative(request, **kwargs):
& & if not request.POST:
& & & & relative = get_object_or_404(Person, pk=kwargs['id']
& & & & form = PersonForm(initial={'last': relative.last})
& & & & return render_to_response('person/form.html', {'form':form})
这例子中 parent 的 last 值是后来得到的,通过 initial 赋给form, 孩子自动填写好父亲的姓氏
/ganiks/p/django-template-and-forms.html
2.3 验证和清理
要让表单运行验证程序,可以显式使用 is_valid 方法
if request.POST:
& & form = PersonForm(request.POST)
& & if form.is_valid:
& & & & new_person = form.save()
& & & & ... ...
执行完验证后,表单对象会得到两个新属性&之一&:
errors -- 包含错误信息的字典
cleaned_data -- 原来绑定到表单的值的干净版本
干净数据意义在于, 输入的数据需要规范化 --- 从一种或多种可能的输入格式转换为一个统一的输出格式,以方便验证和数据库存储
因为 request.POST 中存储的格式一般都是字符串, 经过干净之后
数字变量的字符串 -- int、long
日期变量的字符串 -- datetime
2.4 显示表单
每个Django表单变量都知道自己在HTML标签里要怎么显示, 这种行为是通过 widget 实现的(后面介绍)
first = forms.CharField(max_length=100, required=True)
& & &label for=&id_first&&First:&/label&
& & &input id=&id_first& type=&text& name=&first& maxlength=&100& /&
pf = PersonForm(auto_id=False, label_suffix='')
& & &label&First&/label&
& & &input type=&text& name=&first& maxlength=&100& /&
pf = PersonForm(auto_id='%s_id', label_suffix='?')
& & &label for=&first_id&&First?&/label&
& & &input id=&first_id& type=&text& name=&first& maxlength=&100& /&
2.4.1 显示全部表单
打印表单有多重方法
as_table 默认
2.4.2 逐个显示表单
2.4.3 Widget
每个Django表单变量都知道自己在HTML标签里要怎么显示, 这种行为是通过 widget 实现的, 这个widget子类(比如TextInput)接受了一个 attrs字典,能直接映射到HTML标签的属性上去。
& & middle = forms.CharField(max_length=100,
& & & & widget=forms.TextInput(attrs={'size':3})
&input id=&id_middle& maxlength=&100& type=&text& name=&middle& size=&3& /&
2.4.4 重写一个变量的默认widget
来自定义一个widget LargeTextarea, 默认拥有 40行和100列
from django import newforms as forms
class LargeTextareaWidget(forms.Textarea):
& & def __init__(self, *args, **kwargs):
& & & & kwargs.setdefault('attrs', {}).update({'rows':40, 'cols':100})
& & & & super(LargeTextareaWidget, self).__init__(*args, **kwargs))
这里的 setdefault对字典用到一个技巧,在给定的键存在情况下回返回现有的值, 若给定的键不存在,则返回提供的值;
用在这里,是确保 kwargs 关键字参数字典一定共用 attrs 字典, 不管原来的构造函数参数是什么, 可以 update 来更新attrs字典添加我们需要的默认值。
from django import newsforms as forms
from mysite.myapp.forms import LargeTextareaWidget
class ContentForm(forms.Form):
& & name = forms.CharField()
& & markup = forms.ChoiceField(choices=[('markdown', 'Markdown'),('textile', 'Textile')])
& & text = forms.Textarea(widget=LargeTextareaWidget)
是不是还有优化空间?
Django就是, 有需要的时候, 很容易把各种类和对象替换出去, 从而达到更灵活的自定义。
from django import newforms as forms
class LargeTextareaWidget(forms.Textarea):
& & def __init__(self, *args, **kwargs):
& & & & kwargs.setdefault('attrs', {}).update({'rows':40, 'cols':100})
& & & & super(LargeTextareaWidget, self).__init__(*args, **kwargs))
class LargeTextarea(forms.Field):
& & widget = LargeTextareaWidget
现在可以更方便的使用这个自定义的widget
from django import newsforms as forms
from mysite.myapp.forms import LargeTextareaWidget
class ContentForm(forms.Form):
& & name = forms.CharField()
& & markup = forms.ChoiceField(choices=[('markdown', 'Markdown'),('textile', 'Textile')])
& & #text = forms.Textarea(widget=LargeTextareaWidget)
& & text = LargeTextarea()
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。

我要回帖

更多关于 django crispy forms 的文章

 

随机推荐