me han impresionado la rapidez con que un sitio web funcional puede ir de la mano con las vistas genéricas en los tutoriales. Además, el flujo de trabajo para el procesamiento de formularios es agradable. Usé la clase de ayuda ModelForm para crear un formulario a partir de un modelo que hice y me complació ver que se unía tanta funcionalidad. Cuando utilicé el genérico list_detail.object_detail, me decepcionó que todo lo que podía mostrar eran campos individualmente. Sabía que la clase ModelForm contenía información para el procesamiento, por lo que quería usar ModelForm con una vista genérica.clase basada vista genérica DetailView con un ModelForm revela un error - la forma de proceder?
que estaba pidiendo alrededor en stackoverflow para conseguir una cierta dirección, y apreciar las respuestas y comentarios de varios carteles. He descubierto cómo hacer que esto funcione, pero hay un error en DetailView. La solución incluye una solución alternativa.
Para utilizar un modelview con la vista genérica y obtener todos los campos para hacer automáticamente las siguientes obras:
crear un proyecto, y en ella los pacientes hospitalizados crear aplicaciones.
Si tiene
# inpatients/models.py
class Inpatient(models.Model):
last_name = models.CharField(max_length=30)
first_name = models.CharField(max_length=30,blank=True)
address = models.CharField(max_length=50,blank=True)
city = models.CharField(max_length=60,blank=True)
state = models.CharField(max_length=30,blank=True)
DOB = models.DateField(blank=True,null=True)
notes = models.TextField(blank=True)
def __unicode__(self):
return u'%s, %s %s' % (self.last_name, self.first_name, self.DOB)
class InpatientForm(ModelForm):
class Meta:
model = Inpatient
y
# inpatients/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.views.generic import DetailView
from portal.inpatients.models import *
def formtest(request):
if request.method == 'POST':
form = InpatientForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/inpatients')
else:
form = InpatientForm()
return render_to_response("formtest.html", {'form': form})
class FormDetailView(DetailView):
model=Inpatient
context_object_name='inpatient' # defines the name in the template
template_name_field='inpatient_list_page.html'
def get_object(self):
inpatient=super(FormDetailView,self).get_object()
form=InpatientForm(instance=inpatient)
return form
def get_template_names(self):
return ['inpatient_list_page.html',]
y
#urls.py
from django.conf.urls.defaults import patterns, include, url
from django.views.generic import ListView
from portal.inpatients.models import Inpatient, InpatientForm
from portal.inpatients.views import FormDetailView
urlpatterns = patterns('',
(r'^formtest/$','portal.inpatients.views.formtest'),
(r'^inpatients/$', ListView.as_view(
model=Inpatient, template_name='inpatient_list_page.html')),
(r'^inpatient-detail/(?P<pk>\d+)/$', FormDetailView.as_view()),
)
# with a template containing
{% block content %}
<h2>Inpatients</h2>
<ul>
{% for aninpatient in object_list %}
<li><a href='/inpatient-detail/{{ aninpatient.id }}/'>
{{ aninpatient }}, id={{ aninpatient.id }}</a></li>
{% endfor %}
</ul>
{{ inpatient.as_p }}
{% endblock %}
# Yeah, kind of hokey. The template is for both the list view and detail view.
# Note how the form is rendered with one line - {{ inpatient.as_p }}
funciona. Las instrucciones para usar vistas genéricas basadas en clases viven en https://docs.djangoproject.com/en/1.3/topics/class-based-views/. Las instrucciones son bastante claras. La clave para hacer que las cosas funcionen es redefinir get_object. En la documentación en la sección "Realización de un trabajo extra" que describe muy bien cómo hacer esto, los pasos son para llamar a la versión original de get_object, y luego al trabajo extra. El bit que me di cuenta es que el objeto de retorno puede ser un objeto ModelForm. El objeto que devuelve get_object va directamente a la plantilla en un render. Al tomar el objeto hospitalario recuperado y ejecutarlo a través de InpatientForm, se puede pasar a una vista como un formulario que luego se renderiza.
En cuanto al error: El error en DetailView es que la función get_template_names intenta hacer un nombre de plantilla de una estructura que no existe. En https://code.djangoproject.com/browser/django/trunk/django/views/generic/detail.py en las líneas 127-140 tenemos dentro SingleObjectTemplateResponseMixin.get_template_names:
127 # The least-specific option is the default <app>/<model>_detail.html;
128 # only use this if the object in question is a model.
129 if hasattr(self.object, '_meta'):
130 names.append("%s/%s%s.html" % (
131 self.object._meta.app_label,
132 self.object._meta.object_name.lower(),
133 self.template_name_suffix
134 ))
135 elif hasattr(self, 'model') and hasattr(self.model, '_meta'):
136 names.append("%s/%s%s.html" % (
137 self.model._meta.app_label,
138 self.model._meta.object_name.lower(),
139 self.template_name_suffix
140 ))
El error es que el código en la línea 131 se ejecuta y muere con el mensaje de error objeto < '' ModelFormOptions no tiene atributo 'app_label' >. Concluyo que el objeto _meta está definido. Supongo que el problema es que en un ModelForm se define la clase Meta. Ese Meta probablemente no tiene los campos establecidos que se esperan. La solución consiste simplemente en volver a escribir get_template_names y devolver la plantilla correcta.
Soy nuevo en Django y Python. Agradezco las respuestas y los comentarios de los colaboradores en las siguientes preguntas previas que hice. ( Putting links in list_detail.object_list to list_detail.object_detail, Using form in object_detail, Rolling your own generic views in Django)
¿Qué debo hacer para informar del fallo?
No creo que sea un error, y creo que 'get_object' siempre debe devolver la instancia del modelo no la instancia' ModelForm'. Intente usar [editar CBV] (https://docs.djangoproject.com/en/dev/ref/class-based-views/#editing-views). –
Creo que es un error por varias razones. La documentación no dice que no es válida. La prueba de datos válidos antes de la asignación prueba la existencia de _meta en lugar de los campos reales. La rutina que está buscando la plantilla no encontró la plantilla. Además, en el principal de Do not Repeat Yourself, el ModelForm debe poder entregarse en una plantilla para su representación. – kd4ttc