New in Django 1.0
増田
泰
History and schedule
Version Revision
Date
0.90
1264
2005/11/15
0.95
3491
2006/07/29
0.96
4807
2007/03/23
1.0
8961
2008/09/03
1.0.2
9503
2008/11/18
1.1
-
2009/3/16-20
Scheduled in
New in 1.0
•
Data handling
•
Unicode API
•
FileStorage
•
Auto-escape
•
Model
•
GenericRelation
•
Model inheritance
•
etc.
•
GeoDjango
•
Jython support
•
Sphinx-based docs
•
newforms framework
•
Form media
•
ModelForm
•
FormSet
•
formtools
•
New-Admin
•
ModelAdmin
•
admin.site
forms
•
0.96 で登場した newforms が forms に
•
CSS/JavaScript の指定 (Form media)
•
モデルに基づいたフォーム生成
(ModelForm)
•
フォーム列の操作
(FormSet)
•
プレビュー、ウィザードのツール化
Form Media
•
フォーム特有の
CSSやJavaScriptを
内部クラス
Mediaで指定できる
class DojoPoweredArticleForm(forms.Form):
title = forms.CharField(...)
date = forms.DateTimeField(...)
text = forms.CharField(...
class Media:
css = {'all': ["path/to/css", ...]}
js = ['path/to/js1', ...]
class DojoPoweredArticleForm(forms.Form):
title = forms.CharField(max_length=100, label=u'タイトル')
date = forms.DateTimeField(
widget=forms.TextInput(
attrs=dict(
dojoType="dijit.form.DateTextBox"
)))
text = forms.CharField(
max_length=100, label=u'本文',
widget=forms.Textarea(
attrs=dict(
dojoType='dijit.Editor'
, width='200')))
class Media:
css = dict(all=["css/dojo_tundra.css", ])
js = ['
js/dojo/dojo.js" djConfig="parseOnLoad: true
',
'js/dijit/dijit.js']
<html> <head> {% block head %} {{ form.media }} {{ form.media_extra|safe }} {% endblock head %} </head> <body class="tundra"> {% block content %} <form> <table> {{ form }} </table> </form> {% endblock content %} </body> </html>
ModelForm
•
svn で登場した form_for_model,
form_for_instance は撤廃
•
ModelForm: モデルからフォームを生成
する
Form のサブクラス
•
フィールドの取捨選択が可能に
•
save() できる
•
フィールドパラメタやメソッドをオーバライ
ドできる
ModelForm
Model
Model
Instance
ModelForm
Unbound
Form
Instance
Bound
Form
Instance
request.POST
Initial data (as dict)
validate/save
display
get/create
instantiate
FormSet
•
同じフォームクラスの複数の
インスタンスを扱う
•
リレーションのインライン編集で便利
•
複数エントリフォームの編集で便利
•
エントリの削除・整列を扱える
•
削除
→チェックボックス
•
整列
→整列番号
class OrderForm(forms.Form):
product = forms.CharField(label=u'商品')
quantity = forms.IntegerField(label=u'個数')
...
def form_set_plain(request, template_name='form_set.html'):
params = {}
FormSet =
formset_factory(OrderForm, extra=2)
if request.method=='POST':
formset = FormSet(request.POST, request.FILES)
if formset.is_valid():
params['cdata'] = ('CLEANED_DATA:' +
str(formset.cleaned_data)
else:
formset = FormSet()
params['formset'] = formset
例
: フォームセットを使う
formtools
•
POSTデータの持ち回りを簡単に
•
CSRF対策
•
データのエンコード
•
form_preview
•
フォーム編集
→確認→Submit
•
form_wizard
•
複数ステップのフォーム編集
→Submit
class CustomerInfoForm(forms.Form):
# お客様情報
given_name = forms.CharField(label=u'名前', max_length=100)
...
class DeliveryInfoForm(forms.Form):
# 配送先
delivery_name = forms.CharField(label=u'宛名')
delivery_name_read = forms.CharField(label=u'宛名(読み)')
...
class CreditcardPaymentForm(forms.Form):
vendor = forms.CharField(label=u'カードの種類')
holder_name = forms.CharField(label=u'カードの名義')
...
例
: formtools.form_wizardを使う 1/2
class OrderWizard(wizard.FormWizard):
def done(self, request, form_list):
"""確認ページを表示する。
"""
params, gathered_values = {}
for form in
form_list
:
gathered_values.update(form.cleaned_data)
params['gathered_values'] = gathered_values
return render_to_response(
'confirmation_form.html', params)
def order_wizard(request):
params = {}
wizard =
OrderWizard([CustomerInfoForm, DeliveryInfoForm,
CreditcardPaymentForm])
return wizard(request, extra_context=params)
def confirm(request):
if request.method != 'POST':
raise Http404
form = ConfirmationForm(request.POST.copy())
if form.is_valid():
obj = form.save()
return HttpResponseRedirect(urlreverse('thank_you'))
return render_to_response('failure_report', {'form': form})
New-Admin
•
admin の newforms 化
•
api の公開
•
複数
admin サイトの
立ち上げを可能に
Site
AdminSite
Model
ModelForm
InlineModelForm
Widget
Widget
class PhotoInputWithPreview(admin.widgets.AdminFileWidget): def render(self, name, value, attrs=None):
output = []
output.append(super(PhotoInputWithPreview, self).render( name, value, attrs))
if value and hasattr(value, "url"):
fmt = u'<div id="preview"><img src="%s" /></div>' output.append(fmt %(value.url))
return mark_safe(u''.join(output)) class PhotoForm(forms.ModelForm):
image = forms.ImageField(widget=PhotoInputWithPreview) class Meta: model = Photo class PhotoAdmin(admin.ModelAdmin): form = PhotoForm admin.site.register(Photo, PhotoAdmin)
例
: 画像フィールドにプレビューを挿入する
FileStorage
•
ファイルストレージの抽象化
•
プラットフォームや構成から
ストレージ実装を分離できる
•
仮想的なファイルを表現できる
•
A3やGmailもストレージにできる
•
Object-bound File:
FileFieldやImageFieldの値を表す File
•
model_instance.filefield.save(filename, file)
•
ファイル名を動的に決められる
•
model_instance.filefield.read()
import os.path, os, time
from django.conf import settings
from django.core.files import storage, File import tarfile, StringIO
class TarFileStorage(storage.Storage):
def __init__(self, location=os.path.join(settings.MEDIA_ROOT, 'fs.tar'), base_url=settings.MEDIA_URL):
self.location = os.path.abspath(location) self.base_url = base_url
if not os.path.exists(self.location):
tarfile.open(self.location, 'w').close() # 空のファイル生成。 self.tarfile = tarfile.open(self.location, 'a')
def _open(self, name, mode='rb'): if not self.exists(name): raise IOError('No such file: %s' %name)
return File(self.tarfile.extractfile(name))
def _save(self, name, content): if self.exists(name):
self.tarfile.getmember(name).write(content) else:
ti = tarfile.TarInfo(str(name))
ti.size, ti.mtime = content.size, time.time() self.tarfile.addfile(ti, content)
self.tarfile.close()
self.tarfile = tarfile.open(self.location, 'a') return name
def exists(self, name): try: self.tarfile.getmember(name) return True except KeyError: return False
例
: tarfile をストレージに使う
from django.db import models
from tarfilestorage import TarFileStorage class FileUpload(models.Model):
upload = models.FileField(upload_to='tarfs', storage=TarFileStorage())
例
: tarfile をストレージに使う
slithy-4:kanpy200812 ymasuda$ tar -tvf media/fs.tar