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

Gra*_*ntU 26 django django-models django-views django-class-based-views

假设我想创建一个基于类的视图,它既可以更新可以创建一个对象.根据我之前提出的问题,我可以做以下事情之一:

1)使用2周通用的观点CreateViewUpdateView我认为将意味着有两个网址指向两个不同的类.

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

我有两个问题:

a)哪个更好?

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

scu*_*dha 45

我遇到了一个我想要这样的事情.这是我想出的(请注意,如果您尝试将其用作更新视图并且无法找到所请求的对象,则它将表现为创建视图而不是抛出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)
Run Code Online (Sandbox Code Playgroud)

事实证明,UpdateView并且CreateView从完全相同的类和mixin继承.唯一的区别在于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'
Run Code Online (Sandbox Code Playgroud)

如您所见,CreateView get和post方法在设置self.object = NoneUpdateView设置self.get_object().我所做的就是在我的CreateUpdateView.get_object方法中将这两个结合起来,它试图调用父类' get_object并返回None而不是在没有对象的情况下引发异常.

要在用作更新视图时提供404页面,您可以覆盖as_view并传递一个update_only布尔参数.如果update_onlyTrue,并且视图找不到该对象,则提高404.

  • 这应该是批准的解决方案! (7认同)
  • 谢谢 !只是想知道..为什么不直接从UpdateView继承并覆盖get_object(),get()和post()就像你一样? (5认同)
  • 它甚至更简单; 当既没有提供pk或slug时,get_object会引发一个AttributeError,但是当指定了pk/slug但找不到时,会引发一个DoesNotExist.这意味着您不需要update_only标志,因为您的新get_object仅在未指定pk时返回None,即它将知道何时创建以及何时更新!:-) (2认同)

Pao*_*rre 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
Run Code Online (Sandbox Code Playgroud)

我在Django 1.11中使用了这个解决方案,但我认为它可以在Django 2.0中使用.

更新

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

  • @Bobort,如果你得到的404表明找不到URL中传递的pk.你可能还想提高404. (2认同)

小智 7

所有链接中最简单且基本上是最佳的解决方案

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
Run Code Online (Sandbox Code Playgroud)

就是这样,谢谢@chriskief


Ber*_*pac 5

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

所以:使用两种观点,从一个继承CreateView和其他UpdateView.这些可以处理您可能需要的所有内容,而第二种方法则需要您自己重新发明轮子.如果情况下,当您有使用这两种创建或更新对象时,使用一个混合的选项,也可以或许创建自己的观点,即涵盖了使用情况,从两个继承一些常见的"看家"的代码CreateViewUpdateView.

  • 我觉得"他们最有可能从不同的URL提供服务"的假设是完全错误的.一个常见的URL设计是`objects`的URL上的`GET`返回这些对象的列表,并且对同一URL的`POST`添加该类型的新对象. (7认同)
  • 没有绝对的规则...你也可以对一个没有`id`的url做一些自定义POST,并且POST数据中也没有`id`,只是期望,基于整个POST数据,如果它是创建或更新,服务器就像成年人一样自己计算:) (6认同)
  • 太糟糕了,SO有这么多的答案.基本上"不,你不应该试着这样做,OP,因为这不是我通常做的事情,我不想以你的方式思考它." (5认同)
  • 如果您不知道POST是否会导致创建或更新,该怎么办?那么如何路由到良好的视图(CreateView或UpdateView)? (2认同)
  • “拥有两个单独的视图要简单得多”-我不同意。我有在创建和更新时都需要执行的通用模型内务处理代码。我不明白为什么不应该有CreateOrUpdateView。网址可能包含一个标签,而不是ID。 (2认同)