Django
フォーム
サーチ…
ModelFormの例
サブクラス化することで、既存のモデルクラスからのModelFormを作成ModelForm
:
from django import forms
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['item', 'order_date', 'customer', 'status']
Djangoフォームをゼロから定義する(ウィジェットを使用)
フォームは、モデルと同様の方法で、 django.forms.Form
をサブクラス化することで定義できます。
CharField
、 URLField
、 IntegerField
などのさまざまなフィールド入力オプションを利用できます。
簡単な連絡フォームを定義すると、以下のようになります。
from django import forms
class ContactForm(forms.Form):
contact_name = forms.CharField(
label="Your name", required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
contact_email = forms.EmailField(
label="Your Email Address", required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
content = forms.CharField(
label="Your Message", required=True,
widget=forms.Textarea(attrs={'class': 'form-control'}))
ウィジェットはDjangoのHTMLユーザー入力タグの表現で、フォームフィールド用のカスタムhtmlをレンダリングするために使用できます(例:ここで入力された内容に対してテキストボックスがレンダリングされる)
attrs
は、フォームのレンダリングされたhtmlにそのままコピーされる属性です。
例: content.render("name", "Your Name")
<input title="Your name" type="text" name="name" value="Your Name" class="form-control" />
views.pyの条件に基づいてmodelFormのフィールドを削除する
私たちが次のようなモデルを持っていれば、
from django.db import models
from django.contrib.auth.models import User
class UserModuleProfile(models.Model):
user = models.OneToOneField(User)
expired = models.DateTimeField()
admin = models.BooleanField(default=False)
employee_id = models.CharField(max_length=50)
organisation_name = models.ForeignKey('Organizations', on_delete=models.PROTECT)
country = models.CharField(max_length=100)
position = models.CharField(max_length=100)
def __str__(self):
return self.user
そして、このモデルを次のように使用するモデル形式は、
from .models import UserModuleProfile, from django.contrib.auth.models import User
from django import forms
class UserProfileForm(forms.ModelForm):
admin = forms.BooleanField(label="Make this User Admin",widget=forms.CheckboxInput(),required=False)
employee_id = forms.CharField(label="Employee Id ")
organisation_name = forms.ModelChoiceField(label='Organisation Name',required=True,queryset=Organizations.objects.all(),empty_label="Select an Organization")
country = forms.CharField(label="Country")
position = forms.CharField(label="Position")
class Meta:
model = UserModuleProfile
fields = ('admin','employee_id','organisation_name','country','position',)
def __init__(self, *args, **kwargs):
admin_check = kwargs.pop('admin_check', False)
super(UserProfileForm, self).__init__(*args, **kwargs)
if not admin_check:
del self.fields['admin']
フォームのMetaクラスの下には、フォームフィールドを削除するためにforms.pyからフォームを初期化する際に使用できるinit関数が追加されています (またはその他のアクション)。これについては後で説明します。
したがって、このフォームはユーザー登録目的で使用することができ、フォームのメタクラスに定義されているすべてのフィールドが必要です。しかし、ユーザーを編集するときに同じフォームを使用する場合は、フォームの管理フィールドを表示したくない場合はどうすればよいでしょうか?
いくつかのロジックに基づいてフォームを初期化し、バックエンドから管理フィールドを削除するときに、単に追加の引数を送ることができます。
def edit_profile(request,user_id):
context = RequestContext(request)
user = get_object_or_404(User, id=user_id)
profile = get_object_or_404(UserModuleProfile, user_id=user_id)
admin_check = False
if request.user.is_superuser:
admin_check = True
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information.
profile_form = UserProfileForm(data=request.POST,instance=profile,admin_check=admin_check)
# If the form is valid...
if profile_form.is_valid():
form_bool = request.POST.get("admin", "xxx")
if form_bool == "xxx":
form_bool_value = False
else:
form_bool_value = True
profile = profile_form.save(commit=False)
profile.user = user
profile.admin = form_bool_value
profile.save()
edited = True
else:
print profile_form.errors
# Not a HTTP POST, so we render our form using ModelForm instance.
# These forms will be blank, ready for user input.
else:
profile_form = UserProfileForm(instance = profile,admin_check=admin_check)
return render_to_response(
'usermodule/edit_user.html',
{'id':user_id, 'profile_form': profile_form, 'edited': edited, 'user':user},
context)
ご覧のとおり、以前作成したフォームを使用した簡単な編集例を示しました。私がフォームを初期化したとき、私はTrue
かFalse
を含むadmin_check
変数を渡しました。
profile_form = UserProfileForm(instance = profile,admin_check=admin_check)
今すぐ書いたフォームに気付いたら、 initでここから渡すadmin_check
パラメータをキャッチしようとしていることがadmin_check
ます。値がFalseの場合、フォームからadmin
フィールドを削除して使用するだけです。これはモデルのフォームなので、モデルの管理フィールドはnullにはできません。フォームの投稿に管理フィールドがあるかどうかを確認するだけです。そうでない場合は、ビューの次のコードのビューコードでFalse
に設定します。
form_bool = request.POST.get("admin", "xxx")
if form_bool == "xxx":
form_bool_value = False
else:
form_bool_value = True
Djangoフォームによるファイルアップロード
まず、 settings.py
ファイルにMEDIA_ROOT
とMEDIA_URL
を追加する必要があります
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
ImageField
で作業する場合もありますので、そのような場合は枕のライブラリ( pip install pillow
)をpip install pillow
。そうしないと、次のエラーが発生します。
ImportError: No module named PIL
ピローは、もはや維持されていないPythonイメージングライブラリであるPILのフォークです。ピローはPILと下位互換性があります。
Djangoには、 FileField
とImageField
という2つのフィールドがサーバーにアップロードされます。次の2つのフィールドをフォームに使用する例です
forms.py:
from django import forms
class UploadDocumentForm(forms.Form):
file = forms.FileField()
image = forms.ImageField()
views.py:
from django.shortcuts import render
from .forms import UploadDocumentForm
def upload_doc(request):
form = UploadDocumentForm()
if request.method == 'POST':
form = UploadDocumentForm(request.POST, request.FILES) # Do not forget to add: request.FILES
if form.is_valid():
# Do something with our files or simply save them
# if saved, our files would be located in media/ folder under the project's base folder
form.save()
return render(request, 'upload_doc.html', locals())
upload_doc.html:
<html>
<head>File Uploads</head>
<body>
<form enctype="multipart/form-data" action="" method="post"> <!-- Do not forget to add: enctype="multipart/form-data" -->
{% csrf_token %}
{{ form }}
<input type="submit" value="Save">
</form>
</body>
</html>
フィールドの検証とモデルへのコミット(ユーザーの電子メールの変更)
Djangoには既にユーザパスワードを変更するためのフォームが実装されています。その一例はSetPasswordFormです。
ただし、ユーザーの電子メールを変更するフォームはありません。フォームを正しく使用する方法を理解するには、次の例が重要です。
次の例では、次のチェックを行います。
- 電子メールは実際に変更されました。電子メールの検証やメールのチンパンジーの更新が必要な場合は非常に便利です。
- 電子メールと確認電子メールは同じです。フォームには電子メール用の2つのフィールドがあるため、更新はエラーが発生しにくいものです。
そして最後に、新しい電子メールをユーザーオブジェクトに保存します(ユーザーの電子メールを更新します)。 __init__()
メソッドにはユーザオブジェクトが必要であることに注意してください。
class EmailChangeForm(forms.Form):
"""
A form that lets a user change set their email while checking for a change in the
e-mail.
"""
error_messages = {
'email_mismatch': _("The two email addresses fields didn't match."),
'not_changed': _("The email address is the same as the one already defined."),
}
new_email1 = forms.EmailField(
label=_("New email address"),
widget=forms.EmailInput,
)
new_email2 = forms.EmailField(
label=_("New email address confirmation"),
widget=forms.EmailInput,
)
def __init__(self, user, *args, **kwargs):
self.user = user
super(EmailChangeForm, self).__init__(*args, **kwargs)
def clean_new_email1(self):
old_email = self.user.email
new_email1 = self.cleaned_data.get('new_email1')
if new_email1 and old_email:
if new_email1 == old_email:
raise forms.ValidationError(
self.error_messages['not_changed'],
code='not_changed',
)
return new_email1
def clean_new_email2(self):
new_email1 = self.cleaned_data.get('new_email1')
new_email2 = self.cleaned_data.get('new_email2')
if new_email1 and new_email2:
if new_email1 != new_email2:
raise forms.ValidationError(
self.error_messages['email_mismatch'],
code='email_mismatch',
)
return new_email2
def save(self, commit=True):
email = self.cleaned_data["new_email1"]
self.user.email = email
if commit:
self.user.save()
return self.user
def email_change(request):
form = EmailChangeForm()
if request.method=='POST':
form = Email_Change_Form(user,request.POST)
if form.is_valid():
if request.user.is_authenticated:
if form.cleaned_data['email1'] == form.cleaned_data['email2']:
user = request.user
u = User.objects.get(username=user)
# get the proper user
u.email = form.cleaned_data['email1']
u.save()
return HttpResponseRedirect("/accounts/profile/")
else:
return render_to_response("email_change.html", {'form':form},
context_instance=RequestContext(request))