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

时间:2013-06-19 13:38:17

标签: django django-models django-views django-class-based-views

我想创建基于类的视图更新创建对象。从我制定的previous question开始,我可以做以下事情之一:

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

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

我有两个问题:

a)哪个更好?

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

7 个答案:

答案 0 :(得分:39)

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

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

要在用作更新视图时提供404页面,您可以覆盖update_only并将其传递给update_only布尔参数。如果True<div class="shadow"> <div class="blurred"></div> </div> 且视图无法找到该对象,则提升404.

答案 1 :(得分:7)

@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。

答案 2 :(得分:5)

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

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

答案 3 :(得分: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

答案 4 :(得分:0)

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

答案 5 :(得分: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

答案 6 :(得分:0)

如果您不需要提高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 = [...]