tutorial - Vista basada en la clase de Django para crear y actualizar
httpresponse django example (5)
Digamos que quiero crear una Vista basada en clase que actualiza y crea un objeto. A partir de una pregunta anterior , resolví que podía hacer una de las siguientes cosas:
1) Utilice 2 vistas genéricas, CreateView
y UpdateView
lo que creo que significaría tener dos URL que apuntan a dos clases diferentes.
2) Utilice una vista basada en clase que herede la View
base, lo que creo que significaría tener dos direcciones URL que apuntan a solo 1 clase (creé que hereda la View
).
Tengo dos preguntas:
a) ¿Cuál es mejor?
b) ccbv.co.uk muestra una View
base, pero no veo ningún método documentado de obtención, publicación, etc. ¿es correcto?
¿Por qué necesita manejar tanto la creación como la actualización mediante una única vista? Es mucho más simple tener dos vistas separadas, cada una heredada de su clase de vista genérica respectiva. Si lo desean, pueden compartir el mismo formulario y la misma plantilla, y lo más probable es que se sirvan desde diferentes URL, por lo que no veo lo que obtendría al convertirlo en una vista única.
Entonces: use dos vistas, una CreateView
de CreateView
y la otra de UpdateView
. Estos manejan casi todo lo que pueda necesitar, mientras que el segundo enfoque requeriría que reinventara la rueda usted mismo. Si los casos tienen un código de "mantenimiento" común que se usa al crear o actualizar objetos, la opción de usar un mixin, o quizás pueda crear su propia vista que cubra ambos casos de uso, heredando tanto de CreateView
como de UpdateView
.
Como sugirió @scubabuddha me encontré con una situación similar y utilicé su respuesta modificada como @ mario-orlandi sugirió en su comentario:
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
Utilicé esta solución con Django 1.11, pero creo que puede funcionar en Django 2.0.
Actualizar
Confirmo que esta solución funciona con Django 2.0.7.
Me encontré con una situación en la que quería algo como esto. Esto es lo que se me ocurrió (tenga en cuenta que si está intentando usarlo como una vista de actualización y no puede encontrar el objeto solicitado, se comportará como una vista de creación en lugar de lanzar un 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)
Resulta que UpdateView
y CreateView
heredan de exactamente las mismas clases y combinaciones. La única diferencia está en los métodos get / post. Así es como se definen en la fuente de 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''
Como puede ver, los métodos de creación y publicación de self.object = None
establecen self.object = None
mientras que UpdateView
establece en self.get_object()
. Todo lo que he hecho es combinar esos dos en mi método CreateUpdateView.get_object
que intenta llamar a la clase primaria '' get_object
'' y devuelve None
lugar de generar una excepción si no hay ningún objeto.
Para servir a una página 404 cuando se utiliza como vista de actualización, probablemente podría anular as_view
y pasarle un argumento booleano update_only
. Si update_only
es True
y la vista no puede encontrar el objeto, suba el 404.
Para compartir código entre su UpdateView
y CreateView
, en lugar de crear una clase combinada, puede usar una superclase común como mixin. De esa manera, podría ser más fácil separar las diferentes preocupaciones. Y - puedes reutilizar una gran cantidad de código Django existente.
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
También puede utilizar Django Smartmin, que está inspirado en el CBV de Django. Aquí hay un ejemplo de la documentación: https://smartmin.readthedocs.org/en/latest/quickstart.html