web-dev-qa-db-ja.com

Django作成と更新の両方のクラスベースビュー

Class Based Viewを作成したいとしますupdatescreatesオブジェクトを作成します。 前の質問 から、次のいずれかを実行できることがわかりました。

1)2つの汎用ビューCreateViewおよびUpdateViewを使用します。これは、2つの異なるクラスを指す2つのURLがあることを意味すると思います。

2)ベースViewを継承するクラスベースのビューを使用します。これは、2つのURLが1つのクラスのみを指すことを意味すると思います(Viewを継承するように作成しました)。

2つの質問があります。

a)どちらが良いですか?

b) ccbv.co.uk はベースViewを示していますが、ドキュメントにget、postなどのメソッドが記載されていません。これで正しいですか?

27
GrantU

単一のビューで作成と更新の両方を処理する必要があるのはなぜですか?それぞれがそれぞれの汎用ビュークラスから継承する2つの個別のビューを持つ方がはるかに簡単です。必要に応じて、同じフォームとテンプレートを共有でき、それらは異なるURLから提供される可能性が高いため、単一のビューにすると何が得られるかわかりません。

したがって、2つのビューを使用します。1つはCreateViewから継承し、もう1つはUpdateViewから継承します。これらは、必要となる可能性のあるほとんどすべてを処理しますが、2番目のアプローチでは、自分でホイールを再発明する必要があります。オブジェクトの作成時と更新時の両方で使用される一般的な「ハウスキーピング」コードがある場合、ミックスインを使用するオプション、または両方のケースをカバーする独自のビューを作成して、両方から継承する場合はCreateViewおよびUpdateView

5
Berislav Lopac

私はこのようなものが欲しかった状況に遭遇しました。これが私が思いついたものです(更新ビューとして使用しようとしていて、要求されたオブジェクトが見つからない場合、404をスローするのではなく、作成ビューとして動作することに注意してください)。

_from Django.views.generic.detail import SingleObjectTemplateResponseMixin
from Django.views.generic.edit import ModelFormMixin, ProcessFormView

class CreateUpdateView(SingleObjectTemplateResponseMixin, ModelFormMixin,
        ProcessFormView):

    def get_object(self, queryset=None):
        try:
            return super(CreateUpdateView,self).get_object(queryset)
        except AttributeError:
            return None

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(CreateUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(CreateUpdateView, self).post(request, *args, **kwargs)
_

UpdateViewCreateViewはまったく同じクラスとミックスインを継承していることがわかります。唯一の違いは、get/postメソッドです。 Djangoソース(1.8.2))での定義は次のとおりです。

_class BaseCreateView(ModelFormMixin, ProcessFormView):
    """
    Base view for creating an new object instance.

    Using this base class requires subclassing to provide a response mixin.
    """
    def get(self, request, *args, **kwargs):
        self.object = None
        return super(BaseCreateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = None
        return super(BaseCreateView, self).post(request, *args, **kwargs)


class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
    """
    View for creating a new object instance,
    with a response rendered by template.
    """
    template_name_suffix = '_form'


class BaseUpdateView(ModelFormMixin, ProcessFormView):
    """
    Base view for updating an existing object.

    Using this base class requires subclassing to provide a response mixin.
    """
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseUpdateView, self).post(request, *args, **kwargs)


class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
    """
    View for updating an object,
    with a response rendered by template.
    """
    template_name_suffix = '_form'
_

ご覧のとおり、CreateViewのgetおよびpostメソッドは_self.object = None_を設定し、UpdateViewself.get_object()に設定します。私がやったことは、これら2つを_CreateUpdateView.get_object_メソッドで結合するだけです。これは、親クラスの_get_object_を呼び出そうとして、オブジェクトがない場合に例外を発生させるのではなく、Noneを返します。

更新ビューとして使用するときに404ページを提供するには、おそらく_as_view_をオーバーライドして、それに_update_only_ブール引数を渡すことができます。 _update_only_がTrueであり、ビューがオブジェクトを見つけられない場合は、404を発生させます。

43
scubabuddha

@ scubabuddha によって提案されたように、私は同様の状況に遭遇し、コメントで提案された @ mario-orlandi として修正された彼の回答を使用しました:

from Django.views.generic import UpdateView


class CreateUpdateView(UpdateView):

    def get_object(self, queryset=None):
        try:
            return super().get_object(queryset)
        except AttributeError:
            return None

このソリューションをDjango 1.11で使用しましたが、Django 2.0。

更新

このソリューションがDjango 2.0および2.1で動作することを確認します。

10

UpdateViewCreateViewの間でコードを共有するには、結合されたクラスを作成する代わりに、共通のスーパークラスをミックスインとして使用できます。そうすれば、さまざまな懸念事項を分離する方が簡単な場合があります。そして-多くの既存のDjangoコードを再利用できます。

class BookFormView(PJAXContextMixin):
    template_name = 'library/book_form.html'
    form_class = BookForm

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

    class Meta:
        abstract = True


class BookCreateView(BookFormView, CreateView):
    pass


class FormatUpdateView(BookFormView, UpdateView):
    queryset = Book.objects
0
Risadinha

404を上げる必要がなく、オブジェクトが存在しない場合にすべてのフィールドを空白にする場合は、最初に保存するときにオブジェクトを作成し、存在するときにこれを使用して更新できます。

views.py

from Django.views.generic import UpdateView


class CreateUpdateView(UpdateView):
    model = MyModel
    form_class = MyModelForm

    def get_object(self, queryset=None):
        return self.model.objects.filter(...).first()

forms.py

class MyModelForm(forms.ModelForm):

    class Meta:
        model = MyModel
        fields = [...]
0
alex

Django SmartjanはDjangoのCBVから​​ヒントを得たものです。ドキュメントの例は次のとおりです。 https://smartmin.readthedocs.org/en/latest/quickstart .html

0
iMitwe

すべての中で最もシンプルで基本的に最良のソリューション link

class WorkerUpdate(UpdateView):
form_class = WorkerForm

def get_object(self, queryset=None):

    # get the existing object or created a new one
    obj, created = Worker.objects.get_or_create(mac=self.kwargs['mac'])

    return obj

感謝です @ chriskief

0
vladtyum