Подтвердить что ты не робот

Django Class Based View для создания и обновления

Скажем, я хочу создать представление на основе классов, которое обновляет и создает объект. Из предыдущего вопроса, который я разработал, я мог сделать одну из следующих вещей:

1) Используйте 2 общих представления CreateView и UpdateView которые, я думаю, будут означать наличие двух URL, указывающих на два разных класса.

2) Используйте представление на основе классов, которое наследует базовое View, которое, я думаю, будет означать наличие двух URL, указывающих только на один класс (я создал, который наследует View).

У меня есть два вопроса:

а) Что лучше?

б) ccbv.co.uk показывает базовый View, но я не вижу документированных методов get, post и т.д., это правильно?

4b9b3361

Ответ 1

Почему вам нужно обрабатывать как создание, так и обновление одним представлением? Намного проще иметь два отдельных вида, каждый из которых наследуется от своего общего класса представления. Они могут использовать одну и ту же форму и шаблон, если вы хотите, и они, скорее всего, будут обслуживаться с разных URL-адресов, поэтому я не вижу, что бы вы сделали, сделав его одним видом.

Итак: используйте два вида, один наследующий от CreateView, а другой - от UpdateView. Они обрабатывают практически все, что вам может понадобиться, в то время как для второго подхода вам потребуется изобретать колесо самостоятельно. Если случаи, когда у вас есть общий код "домашнего хозяйства", который используется как при создании, так и при обновлении объектов, возможность использования mixin, или вы можете создать собственное представление, которое охватывает оба варианта использования, наследуя как от CreateView, так и UpdateView.

Ответ 2

Я столкнулся с ситуацией, когда хотел чего-то подобного. Вот что я придумал (обратите внимание, что если вы пытаетесь использовать его в качестве вида обновления и не можете найти запрошенный объект, он будет вести себя как представление create, а не метать 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)

Оказывается, что UpdateView и CreateView наследуются от одних и тех же классов и mixins. Единственное различие заключается в методах 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, а UpdateView устанавливает его в self.get_object(). Все, что я сделал, это объединить эти два метода CreateUpdateView.get_object, который пытается вызвать родительский класс get_object и возвращает None вместо того, чтобы создавать исключение, если нет объекта.

Чтобы обслуживать страницу 404 при использовании в качестве вида обновления, возможно, вы можете переопределить as_view и передать ему логический аргумент update_only. Если update_only есть True, и представление не может найти объект, тогда поднимите значение 404.

Ответ 3

По предложению @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.

Ответ 4

Чтобы совместно использовать код между UpdateView и CreateView, вместо создания комбинированного класса вы можете использовать обычный суперкласс как mixin. Таким образом, было бы легче разделить различные проблемы. И - вы можете повторно использовать много существующего кода 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