我想创建基于类的视图,更新和创建对象。从我制定的previous question开始,我可以做以下事情之一:
1)使用2个通用视图CreateView
和UpdateView
,我认为这意味着有两个URL指向两个不同的类。
2)使用继承基类View
的基于类的视图,我认为这意味着有两个URL指向只有1个类(我创建了继承View
)。
我有两个问题:
a)哪个更好?
b)ccbv.co.uk显示基础View
,但我没有看到记录的任何get,post等方法,这是正确的吗?
答案 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)
事实证明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'
如您所见,在self.object = None
将UpdateView
设置为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,或者您可以创建自己的视图来涵盖两个用例,继承自CreateView
和UpdateView
。
答案 3 :(得分:1)
要在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
答案 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 = [...]