Django Class Based View для создания и обновления
Скажем, я хочу создать представление на основе классов, которое обновляет и создает объект. Из предыдущего вопроса, который я разработал, я мог сделать одну из следующих вещей:
1) Используйте 2 общих представления CreateView
и UpdateView
которые, я думаю, будут означать наличие двух URL, указывающих на два разных класса.
2) Используйте представление на основе классов, которое наследует базовое View
, которое, я думаю, будет означать наличие двух URL, указывающих только на один класс (я создал, который наследует View
).
У меня есть два вопроса:
а) Что лучше?
б) ccbv.co.uk показывает базовый View
, но я не вижу документированных методов get, post и т.д., это правильно?
Ответы
Ответ 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
Ответ 5
Вы также можете использовать Django Smartmin, который вдохновлен CBV Django. Вот пример из документации: https://smartmin.readthedocs.org/en/latest/quickstart.html