40

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

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

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

我有两个问题:

a) 哪个更好?

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

4

7 回答 7

57

我遇到了我想要这样的东西的情况。这是我想出的(请注意,如果您尝试将其用作更新视图并且找不到请求的对象,它将表现为创建视图而不是抛出 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为. 我所做的只是在我的方法中结合这两者,它试图调用父类并返回而不是在没有对象的情况下引发异常。UpdateViewself.get_object()CreateUpdateView.get_objectget_objectNone

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

于 2015-06-19T22:29:42.063 回答
19

就像@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.2

于 2018-01-05T15:39:18.893 回答
5

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

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

于 2019-02-25T12:03:12.613 回答
2

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

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

于 2013-06-19T16:08:11.957 回答
1

如果您不需要引发 404 并且如果对象不存在并且希望所有字段为空白,则在第一次保存时创建对象并在存在时更新您可以使用它。

视图.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()

表格.py

class MyModelForm(forms.ModelForm):

    class Meta:
        model = MyModel
        fields = [...]
于 2020-02-28T15:10:50.480 回答
0

UpdateView要在你的and之间共享代码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
于 2016-07-24T09:59:58.923 回答
0

You can also use Django Smartmin which is inspired from CBV of Django. Here is an example from the documentation : https://smartmin.readthedocs.org/en/latest/quickstart.html

于 2015-10-06T07:31:27.190 回答