基于Django类的创建和更新视图

问题描述 投票:25回答:6

假设我想创建一个基于类的视图,它既可以更新也可以创建一个对象。从我制定的previous question,我可以做以下事情之一:

1)使用2个通用视图CreateViewUpdateView,我认为这意味着有两个URL指向两个不同的类。

2)使用基于类的视图继承基础View,我认为这意味着有两个URL指向只有1个类(我创建了继承View)。

我有两个问题:

a)哪个更好?

b)ccbv.co.uk显示基础View,但我没有看到任何get,post等方法记录,这是正确的吗?

django django-models django-views django-class-based-views
6个回答
5
投票

为什么需要通过单个View处理创建和更新?拥有两个单独的视图要简单得多,每个视图都从其各自的通用视图类继承。如果您愿意,他们可以共享相同的表单和模板,并且他们最有可能来自不同的URL,所以我看不到将它变成单个视图会得到什么。

所以:使用两个视图,一个继承自CreateView,另一个继承自UpdateView。这些可以处理您可能需要的所有内容,而第二种方法则需要您自己重新发明轮子。如果您在创建或更新对象时使用了一些常用的“内务”代码,使用mixin的选项,或者您可以创建自己的视图,涵盖两个用例,继承CreateViewUpdateView


42
投票

我遇到了一个我想要这样的事情。这是我想出的(请注意,如果您尝试将其用作更新视图并且无法找到所请求的对象,则它将表现为创建视图而不是抛出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继承了完全相同的类和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_onlyTrue并且视图找不到对象,则提升404。


10
投票

@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中使用。

Update

我确认这个解决方案适用于Django 2.0和2.1。


1
投票

要在UpdateViewCreateView之间共享代码,而不是创建组合类,您可以使用常见的超类作为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

0
投票

你也可以使用灵感来自Django的CBV的Django Smartmin。以下是文档中的示例:https://smartmin.readthedocs.org/en/latest/quickstart.html


0
投票

最简单,基本上是所有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

© www.soinside.com 2019 - 2024. All rights reserved.