3

ユーザーが支払いの注文を送信するDjangoアプリがあります。明らかに、セキュリティは重要です。作成するコードの量を最小限に抑え、セキュリティ ホールの発生を回避し、メンテナンスを容易にしたいと考えています。

モデルは単純です。

class Order(models.Model):
    user = models.ForeignKey(User)
    created = models.DateTimeField()
    paid = models.DateTimeField(null=True, blank=True)
    items = models.ManyToManyField(Item)

CreateViewを使用してOrder のインスタンスを作成しています。

class OrderView(CreateView):
    model = Order
    form_class = OrderForm

これらのインスタンスの特定のフィールドに値を適用したいと考えています。たとえば、インスタンスuserフィールドを現在ログインしているユーザーに設定します。ユーザーがこのフィールドの値を変更できる可能性を望んでいないので、フォームにまったく表示したくありません。したがって、カスタムModelFormを使用して、これらのフィールドをフォームから削除します。

class OrderForm(forms.ModelForm):
    class Meta:
        model = Order
        # For security, we control exactly which fields are placed
        # in the form, rather than excluding some:
        fields = ('items',)

次に、新しく作成された Order インスタンスのuserフィールドを現在ログインしているユーザーに設定します。これを行う最善の方法についてのドキュメントが見つかりません。

(A)保存する前にフォームのメソッドをオーバーライドしsave()てオブジェクトを変更することはできますが、このコードは、フィールドについて何も知らないフォームに属していないように感じuserます。requestまた、現在のユーザーを特定するために必要な hereへのアクセス権もありません。しかし、次のようになります。

class OrderForm(forms.ModelForm):
    def save(self, commit=True):
        instance = super(OrderForm, self).save(commit=False)
        instance.user = get_request_magic().user
        if commit:
            instance.save()
        return instance

(B)ビューのform_validメソッドをオーバーライドして、この質問のクラスベース バージョンのように、commit=False でオブジェクトを保存できます。しかし、スーパークラス メソッドを直接呼び出すことはできません。コミットを無効にする方法がないため、オブジェクトを保存するため、form_valid厄介な世代を手動でスキップする必要があります。その苦情は別として、これは私がこれまでに見つけた最良の方法のように見えます:

class OrderView(CreateView):
    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.user = self.request.user
        self.object.save()
        return super(ModelFormMixin, self).form_valid(form)

(C)CreateViewオブジェクトを保存する前に変更できるようにするためのフックを追加するの代替を書くことができます。しかし、それはより多くのボイラープレートと重複のように感じます.

(D)値を入力するフォーム フィールドがないため、initialを指定できません。無視されます。

他のアイデアはありますか?(B) が最良の選択肢である場合、どのスーパークラスのform_validメソッドを呼び出したいかを手動で指定するハックな方法を回避する方法はありますか?

4

3 に答える 3

2

Django ユーザーのChalettes が質問に答えてくれました。

これは、form_valid をオーバーライドすることで実現できます。

class OrderCreateViewMixin(CreateView):
    def form_valid(self, form):
        form.instance.user = request.user
        return super(OrderCreateViewMixin, self).form_valid(form)

これは、ドキュメントの右側の部分に向けて私を指摘しました:

class AuthorCreate(CreateView):
    form_class = AuthorForm
    model = Author

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super(AuthorCreate, self).form_valid(form)

これは間違いなく、これまでに見つけた中で最もシンプルでクリーンな答えです。instance少し醜いメンバーに直接アクセスしますが、フォームを変更する必要はありません。ただし、少なくとも公式に文書化されているため、壊れることはほとんどありません。

于 2013-01-03T11:45:30.840 に答える
0

これにはおそらく複数のアプローチがあります。私はこれをします:

リクエストを受け取るフォームにコンストラクターを作成します。

def __init__(self, *args, **kwargs):
        request = kwargs.pop('request', None)
        super(OrderForm, self).__init__(*args, **kwargs)
        self.request = request

POST 処理用のフォームを作成するときは、次のようにインスタンス化します。

form = OrderForm(data=request.POST, request=request)

これで、save() メソッドで、参照によってリクエストのユーザーにアクセスできself.request.user、モデルに応じて設定できます。

于 2012-12-05T17:49:24.533 に答える
0

この状況を CBV で処理する方法として、保存されていないモデルのインスタンスをフォームに渡します。これが私がやった方法です:

class OrderView(CreateView):
    def get_form_kwargs(self):
        self.object = Order(user=self.request.user)
        return super(OrderView, self).get_form_kwargs()

CreateViewとの両方がフォーム kwargs にUpdateView追加され、値が に設定されます。 instanceself.object

他の唯一の方法は、既に述べたこと以外に、同じ要素からビュー クラスを構築CreateViewし、get メソッドと post メソッドを変更してself.objectそこに入力することです。プロジェクトで多くの作成ビューが必要なときに、私はそれを行いました:

class OrderView(SingleObjectTemplateResponseMixin, ModelFormMixin, ProcessFormView):
    template_name_suffix = '_form'

    def get(self, request, *args, **kwargs):
        self.object = Order(user=request.user)
        return super(OrderView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = Order(user=request.user)
        return super(OrderView, self).post(request, *args, **kwargs)

再利用されるより一般化されたバージョンは次のとおりです: https://gist.github.com/4439975

于 2013-01-03T01:14:39.720 に答える