Esto se solucionó en Django 1.9 con form_kwargs .
Tengo un formulario de Django que se ve así:
class ServiceForm(forms.Form):
option = forms.ModelChoiceField(queryset=ServiceOption.objects.none())
rate = forms.DecimalField(widget=custom_widgets.SmallField())
units = forms.IntegerField(min_value=1, widget=custom_widgets.SmallField())
def __init__(self, *args, **kwargs):
affiliate = kwargs.pop('affiliate')
super(ServiceForm, self).__init__(*args, **kwargs)
self.fields["option"].queryset = ServiceOption.objects.filter(affiliate=affiliate)
Llamo a este formulario con algo como esto:
form = ServiceForm(affiliate=request.affiliate)
¿Dónde request.affiliate
está el usuario conectado? Esto funciona según lo previsto.
Mi problema es que ahora quiero convertir este formulario único en un conjunto de formularios. Lo que no puedo entender es cómo puedo pasar la información del afiliado a los formularios individuales al crear el conjunto de formularios. De acuerdo con los documentos para hacer un formulario de esto, necesito hacer algo como esto:
ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)
Y luego necesito crearlo así:
formset = ServiceFormSet()
Ahora, ¿cómo puedo pasar afiliado = request.affiliate a los formularios individuales de esta manera?
fuente
functools.partial
lugar de Djangodjango.utils.functional.curry
. Hacen lo mismo, excepto quefunctools.partial
devuelve un tipo invocable distinto en lugar de una función Python normal, y elpartial
tipo no se vincula como un método de instancia, que resuelve perfectamente el problema que este hilo de comentarios se dedicó en gran medida a la depuración.Manera oficial del documento
Django 2.0:
https://docs.djangoproject.com/en/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
fuente
Construiría la clase de formulario dinámicamente en una función, para que tenga acceso al afiliado a través del cierre:
Como beneficio adicional, no tiene que volver a escribir el conjunto de consultas en el campo de opción. La desventaja es que la subclase es un poco funky. (Cualquier subclase debe hacerse de manera similar).
editar:
En respuesta a un comentario, puede llamar a esta función sobre cualquier lugar donde usaría el nombre de la clase:
fuente
Esto es lo que funcionó para mí, Django 1.7:
Espero que ayude a alguien, me tomó el tiempo suficiente para resolverlo;)
fuente
staticmethod
se necesita aquí?Me gusta la solución de cierre por ser "más limpia" y más Pythonic (por lo tanto, +1 a la respuesta de mmarshall) pero los formularios de Django también tienen un mecanismo de devolución de llamada que puede usar para filtrar conjuntos de consultas en conjuntos de formularios.
Tampoco está documentado, lo que creo que es un indicador de que a los desarrolladores de Django no les gustará tanto.
Entonces, básicamente, crea su conjunto de formularios de la misma manera pero agrega la devolución de llamada:
Esto está creando una instancia de una clase que se ve así:
Esto debería darte la idea general. Es un poco más complejo hacer que la devolución de llamada sea un método de objeto como este, pero le brinda un poco más de flexibilidad en lugar de hacer una devolución de llamada de función simple.
fuente
Quería colocar esto como un comentario a la respuesta de Carl Meyers, pero como eso requiere puntos, simplemente lo coloqué aquí. Me llevó 2 horas entenderlo, así que espero que ayude a alguien.
Una nota sobre el uso de inlineformset_factory.
Utilicé esa solución por mi cuenta y funcionó perfectamente, hasta que la probé con inlineformset_factory. Estaba ejecutando Django 1.0.2 y obtuve una extraña excepción KeyError. Actualicé a la última troncal y funcionó directamente.
Ahora puedo usarlo de manera similar a esto:
fuente
modelformset_factory
. Gracias por esta respuesta!A partir de commit e091c18f50266097f648efc7cac2503968e9d217 el martes 14 de agosto 23:44:46 2012 +0200 la solución aceptada ya no puede funcionar.
La versión actual de la función django.forms.models.modelform_factory () utiliza una "técnica de construcción de tipos", que llama a la función type () en el formulario pasado para obtener el tipo de metaclase, luego usa el resultado para construir un objeto de clase de su escriba sobre la marcha ::
Esto significa incluso un
curry
partial
objeto ed o pasado en lugar de una forma "hace que el pato te muerda", por así decirlo: llamará a una función con los parámetros de construcción de unModelFormClass
objeto, devolviendo el mensaje de error ::Para evitar esto, escribí una función de generador que usa un cierre para devolver una subclase de cualquier clase especificada como primer parámetro, que luego llama
super.__init__
despuésupdate
de enviar los kwargs con los que se proporcionan en la llamada de la función del generador ::Luego, en su código, llamará a la fábrica de formularios como ::
advertencias:
fuente
La solución de Carl Meyer se ve muy elegante. Intenté implementarlo para modelformsets. Tenía la impresión de que no podía llamar a métodos estáticos dentro de una clase, pero lo siguiente funciona inexplicablemente:
En mi opinión, si hago algo como esto:
Luego, la palabra clave "solicitud" se propaga a todos los formularios de miembros de mi conjunto de formularios. Estoy contento, pero no tengo idea de por qué está funcionando, parece estar mal. ¿Alguna sugerencia?
fuente
MyFormSet.form.Meta.model
.MyFormSet.form().Meta.model
. Obvio realmente.Pasé algún tiempo tratando de resolver este problema antes de ver esta publicación.
La solución que se me ocurrió fue la solución de cierre (y es una solución que he usado antes con los formularios modelo Django).
Probé el método curry () como se describió anteriormente, pero no pude hacerlo funcionar con Django 1.0, así que al final volví al método de cierre.
El método de cierre es muy claro y la única rareza es que la definición de clase está anidada dentro de la vista u otra función. ¡Creo que el hecho de que esto me parezca extraño es un problema de mi experiencia previa en programación y creo que alguien con experiencia en lenguajes más dinámicos no pestañearía!
fuente
Tuve que hacer algo similar. Esto es similar a la
curry
solución:fuente
En base a esta respuesta , encontré una solución más clara:
Y ejecutarlo a la vista como
fuente
Soy un novato aquí, así que no puedo agregar comentarios. Espero que este código también funcione:
en cuanto a agregar parámetros adicionales al conjunto
BaseFormSet
de formularios en lugar del formulario.fuente