サーチ…


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をサブクラス化することで定義できます。
CharFieldURLFieldIntegerFieldなどのさまざまなフィールド入力オプションを利用できます。

簡単な連絡フォームを定義すると、以下のようになります。

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)

ご覧のとおり、以前作成したフォームを使用した簡単な編集例を示しました。私がフォームを初期化したとき、私はTrueFalseを含む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_ROOTMEDIA_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には、 FileFieldImageFieldという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))


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow