2011-06-25 18 views
7

Estoy tratando de usar la clase genérica CreateView para manejar formularios para un conjunto de modelos heredados de la misma clase base.Django: vistas paramétricas basadas en clases

class BaseContent(models.Model): 
    ... 

class XContent(BaseContent): 
    ... 

class YContent(BaseContent): 
    ... 

Para mantener las cosas SECAS, quiero definir una clase CreateView que manejará todas las clases heredadas de BaseContent.

el patrón de URL para ese punto de vista es:

url(r'^content/add/(?P<model_name>\w+)/$', ContentCreateView.as_view(), name='content_add') 

Algo como esto debería funcionar:

class ContentCreateView(CreateView): 
    template_name = 'content_form.html' 

    def get_model(self, request): 
     # 'content' is the name of the application; model_name is 'xcontent', 'ycontent', ... 
     return ContentType.objects.get_by_natural_key('content', self.model_name) 

Pero me estoy haciendo esta excepción:

ContentCreateView is missing a queryset. Define ContentCreateView.model, ContentCreateView.queryset, or override ContentCreateView.get_object(). 

Esta sugerencia no lo hace parece sostenerse ya que no estoy dispuesto a establecer un atributo de clase como model o queryset t o mantener el formulario del modelo generado dinámico. Anular el get_object no parece relevante para crear un objeto.

Intenté sobreescribir get_queryset() pero este método no acepta el parámetro request, ni tengo acceso a self.model_name que proviene del patrón de url.

En pocas palabras, ¿cómo puedo hacer que un CreateView use un formulario dinámico basado en un parámetro pasado desde la url?

Gracias.

+0

creo que esa solicitud y nombre_del_modelo se establecería como variables de instancia, por lo que podría auto .request y self.model_name dentro del método get_queryset(). No intenté ese pensamiento. – bmihelac

+1

sí, la clase de vista que es un antecesor de CreateView establece los kwargs de la url como variables de instancia. pero 'self.model_name' no es accesible para' get_queryset() 'ya que proviene de otra mixin mientras' auto.request' es. si paso el nombre del modelo como un parámetro 'get', podré hacer lo que quiera, pero no será agradable. imo, la forma en que la herencia y las mezclas están organizadas en vistas basadas en clases y la falta de documentación hace que sea muy complicado rastrear los métodos y atributos de clase. – omat

+1

¿No puede simplemente crear clases de formulario para cada uno de los modelos y superar el método get_form_class de 'ModelFormMixin' para obtener el formulario relevante para la vista en función de los parámetros de solicitud? – vimukthi

Respuesta

1

puede establecer el atributo model de Su joven urls.py, dependiendo de la dirección URL que se llamó:

url(r'^content/add/x/$', 
    ContentCreateView.as_view(model=XContent), name='x_content_add'), 
url(r'^content/add/y/$', 
    ContentCreateView.as_view(model=YContent), name='y_content_add') 

Admito que no es perfecta, ya que se está repitiendo un poco, pero por lo tanto tiene la ventaja de tener ¡diferentes nombres para la misma vista, según el modelo! Además de eso, también podría hacer algo similar al anular form_class ...

+0

as_view() no parece aceptar argumentos. la forma en que sugeriste plantea: 'as_view() toma exactamente 1 argumento (2 dado)'. Modifiqué el patrón de URL de esta manera: 'url (r '^ add/x/$', ContentCreateView.as_view(), {'queryset': XContent.objects.all()}) 'pero el kwarg no parece pasarse a la instancia de la clase:' ContentCreateView no tiene un queryset'. – omat

+0

Disculpe mi culpa, por supuesto que tiene que pasarlo como kwargs, no como dict, editó la respuesta. –

+0

gracias por la actualización, está bien ahora. Espero que se documentará pronto, aunque no es fácil con múltiples niveles de herencia múltiple. – omat

1

Tuve este problema durante algún tiempo, pero encontré la solución. Es necesario reemplazar el método de envío, definido en as_view() (django.views.generic.base), algo como esto:

class ContentCreateView(CreateView):  
    def dispatch(self, request, *args, **kwargs): 
     for app in ['foo', 'bar']: 
      model = models.get_model(app, kwargs['modelname']) 
      if model: 
       self.model = model 
       break 

     return super(GenericEdit, self).dispatch(request, *args, **kwargs) 
    ... 
    ... 
Cuestiones relacionadas