ModelFormを使ってデータ編集機能実装
ほかにやっている人(id:perezvon:20080202:1201931223)がいましたが
Djangoの1.0でModelForm(モデルより生成されるフォーム)を使って、データ編集機能を実装してみました。
Modelの定義
from django.db import models from django.contrib.auth.models import User ... class Todo(models.Model): title = models.CharField(max_length=200) description = models.TextField(blank=True, max_length=4000) datetime_created = models.DateTimeField(auto_now_add=True) datetime_updated = models.DateTimeField(auto_now=True) is_finished = models.BooleanField(default=False) priority=models.ForeignKey(Priority) category=models.ForeignKey(Category) user = models.ForeignKey(User) def __unicode__(self): """docstring for __unicode__""" return self.title
ModelForm
上記のモデルをもとに生成されるフォームの定義を行います。
from django import forms from djsite.todo.models import Category,Todo .... class TodoEditForm(forms.ModelForm): search_title = forms.CharField(widget=forms.HiddenInput, max_length=100, label=u'タイトル', required=False) search_category = forms.IntegerField(widget=forms.HiddenInput, required=False,label=u'カテゴリー') search_include_finished = forms.BooleanField(required=False, widget=forms.HiddenInput,label=u'完了分も含める') id = forms.IntegerField(widget=forms.HiddenInput, required=False,label=u'id') class Meta: model = Todo exclude = ('is_finished','user',)
-
- Mataという内部クラスを定義、そのmodel属性にモデルを指定するとそのモデルからのフィームインスタンスが生成されるようになります。
- id属性は、変更用にフォームページが開かれたときにモデルの主キーを格納するため定義しています。
- その他の「search_XXX」属性は、遷移もとページを再表示するためのパラメータを格納するために追加定義しました。今回の具体例としては、一覧の検索条件を格納するためのものです。
Viewの定義
以下は、編集操作のためのViewです。GETリクエストの場合は、フォームページの表示を行います。POSTの場合を更新処理を行い、一覧表示のページに戻るようにしています。
from django.http import HttpResponse,HttpResponseRedirect from django.shortcuts import render_to_response from djsite.todo.models import Todo from djsite.todo.forms import TodoSearchForm, TodoEditForm ..... def edit_todo(request): if request.POST: if request.POST.has_key('id') and len(request.POST['id']): try: todo = Todo.objects.get(id=int(request.POST['id'])) except Exception, e: render_to_response('error.html') form = TodoEditForm(request.POST, instance=todo) else: form = TodoEditForm(request.POST) if form.is_valid(): user = request.user todo = form.save(commit=False) todo.user_id = user.id todo.save() # list へ戻る cleaned = form.clean() search_form = TodoSearchForm() args = [] if cleaned['search_category'] : args.append("category=" + str(cleaned['search_category'])) if cleaned['search_title']: args.append("title=" + str(cleaned['search_title'])) if cleaned['search_include_finished']: args.append("include_finished=" + str(cleaned['search_include_finished'])) response = HttpResponseRedirect('list?' + '&'.join(args)) return response else: print form.errors return render_to_response('edit_todo.html', dict(form=form, method="post")) else: form = TodoEditForm(request.GET) if request.GET.has_key('id'): try: todo = Todo.objects.get(id=int(request.GET['id'])) except Exception, e: return render_to_response('error.html') form = TodoEditForm(instance=todo) return render_to_response('edit_todo.html', dict(form=form,method="get"))
テンプレート
以下は、編集ページのテンプレート(edit_todo.html)です。
<head> </head> <body> <form action="./edit" method="POST"> <table> <tr> <td> <label class="fortextinput" for="id_title"> タイトル: </label> </td> <td> {{ form.title }} {%if form.title.errors %} {%ifequal method 'post' %} <span style="color: red;"> {{ form.title.errors|join:", " }} </span> {% endifequal %} {% endif %} </td> </tr> <tr> <td> <label class="fortextinput" for="id_description"> 内容: </label> <td> {{ form.description }} {%ifequal method 'post' %} {%if form.description.errors %} <span style="color: red;"> {{ form.description.errors|join:", " }} </span> {% endif %} {% endifequal %} </td> </tr> <tr> <td> <label class="fortextinput" for="id_description"> 優先度: </label> <td> {{ form.priority }} {% ifequal method 'post' %} {%if form.priority.errors %} <span style="color: red;"> {{ form.priority.errors|join:", " }} </span> {% endif %} {% endifequal %} </td> </tr> <tr> <td> <label class="fortextinput" for="id_description"> カテゴリー: </label> <td> {{ form.category }} {% ifequal method 'post' %} {%if form.category.errors %} <span style="color: red;"> {{ form.category.errors|join:", " }} </span> {% endif %} {% endifequal %} </td> </tr> {{ form.id }} {{ form.search_category }} {{ form.search_title }} {{ form.search_include_finished }} </table> <input type="submit"> </form> </body> </html>
-
- エラーを表示する条件として「{% ifequal method 'post' %}」というのを入れていますが、これは、GETによる初期表示時にエラーメッセージが表示されないようにするための条件です。「method」という変数は、view関数からこのテンプレートを表示するさいに渡しているものです(標準で定義されるわけではないです)。