Ce problème a été corrigé dans Django 1.9 avec form_kwargs .
J'ai un formulaire Django qui ressemble à ceci:
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)
J'appelle ce formulaire avec quelque chose comme ceci:
form = ServiceForm(affiliate=request.affiliate)
Où request.affiliate
est l'utilisateur connecté. Cela fonctionne comme prévu.
Mon problème est que je veux maintenant transformer ce formulaire unique en un formset. Ce que je ne peux pas comprendre, c'est comment je peux transmettre les informations d'affiliation aux formulaires individuels lors de la création du formset. Selon la documentation, pour créer un formulaire à partir de cela, je dois faire quelque chose comme ceci:
ServiceFormSet = forms.formsets.formset_factory(ServiceForm, extra=3)
Et puis j'ai besoin de le créer comme ceci:
formset = ServiceFormSet()
Maintenant, comment puis-je transmettre affiliate = request.affiliate aux formulaires individuels de cette façon?
la source
functools.partial
lieu de Djangodjango.utils.functional.curry
. Ils font la même chose, sauf quefunctools.partial
retourne un type appelable distinct au lieu d'une fonction Python régulière, et lepartial
type ne se lie pas en tant que méthode d'instance, ce qui résout parfaitement le problème que ce fil de commentaires était largement consacré au débogage.Document officiel Way
Django 2.0:
https://docs.djangoproject.com/en/2.0/topics/forms/formsets/#passing-custom-parameters-to-formset-forms
la source
Je créerais la classe de formulaire dynamiquement dans une fonction, afin qu'elle ait accès à l'affilié via la fermeture:
En prime, vous n'avez pas à réécrire le jeu de requête dans le champ d'option. L'inconvénient est que le sous-classement est un peu génial. (Toute sous-classe doit être créée de la même manière.)
Éditer:
En réponse à un commentaire, vous pouvez appeler cette fonction à tout endroit où vous utiliseriez le nom de la classe:
la source
C'est ce qui a fonctionné pour moi, Django 1.7:
J'espère que cela aide quelqu'un, cela m'a pris assez de temps pour le comprendre;)
la source
staticmethod
est nécessaire ici?J'aime la solution de fermeture pour être «plus propre» et plus pythonique (donc +1 à la réponse mmarshall) mais les formulaires Django ont aussi un mécanisme de rappel que vous pouvez utiliser pour filtrer les ensembles de requêtes dans les ensembles de formulaires.
Ce n'est pas non plus documenté, ce qui, je pense, est un indicateur que les développeurs de Django pourraient ne pas l'aimer autant.
Donc, vous créez fondamentalement votre formset de la même manière, mais ajoutez le rappel:
Ceci crée une instance d'une classe qui ressemble à ceci:
Cela devrait vous donner une idée générale. C'est un peu plus complexe de faire du callback une méthode objet comme celle-ci, mais vous donne un peu plus de flexibilité que de faire un simple rappel de fonction.
la source
Je voulais placer cela comme un commentaire à la réponse de Carl Meyers, mais comme cela nécessite des points, je viens de le placer ici. Cela m'a pris 2 heures pour comprendre alors j'espère que cela aidera quelqu'un.
Une note sur l'utilisation de inlineformset_factory.
J'ai utilisé cette solution moi-même et cela a fonctionné parfaitement, jusqu'à ce que je l'ai essayé avec le inlineformset_factory. J'utilisais Django 1.0.2 et j'ai eu une étrange exception KeyError. J'ai mis à niveau vers le dernier coffre et cela a fonctionné directement.
Je peux maintenant l'utiliser comme ceci:
la source
modelformset_factory
. Merci pour cette réponse!À partir du commit e091c18f50266097f648efc7cac2503968e9d217 le Tue Aug 14 23:44:46 2012 +0200, la solution acceptée ne peut plus fonctionner.
La version actuelle de la fonction django.forms.models.modelform_factory () utilise une "technique de construction de type", appelant la fonction type () sur le formulaire passé pour obtenir le type de métaclasse, puis utilisant le résultat pour construire un objet de classe de son tapez à la volée ::
Cela signifie que même un
curry
ed ou unpartial
objet passé au lieu d'un formulaire "provoque le canard à vous mordre" pour ainsi dire: il appellera une fonction avec les paramètres de construction d'unModelFormClass
objet, renvoyant le message d'erreur:Pour contourner ce problème, j'ai écrit une fonction de générateur qui utilise une fermeture pour renvoyer une sous-classe de n'importe quelle classe spécifiée comme premier paramètre, qui appelle ensuite
super.__init__
après avoirupdate
ing les kwargs avec ceux fournis lors de l'appel de la fonction de générateur:Ensuite, dans votre code, vous appellerez la fabrique de formulaires comme suit:
mises en garde:
la source
La solution de Carl Meyer est très élégante. J'ai essayé de l'implémenter pour les modèles de formulaires. J'avais l'impression que je ne pouvais pas appeler de méthodes statiques au sein d'une classe, mais ce qui suit fonctionne inexplicablement:
À mon avis, si je fais quelque chose comme ça:
Ensuite, le mot-clé "request" est propagé à tous les formulaires membres de mon formset. Je suis content, mais je ne sais pas pourquoi cela fonctionne - cela semble faux. Aucune suggestion?
la source
MyFormSet.form.Meta.model
.MyFormSet.form().Meta.model
. Évident vraiment.J'ai passé du temps à essayer de résoudre ce problème avant de voir cette publication.
La solution que j'ai trouvée était la solution de fermeture (et c'est une solution que j'ai déjà utilisée avec les formulaires modèles Django).
J'ai essayé la méthode curry () comme décrit ci-dessus, mais je ne pouvais tout simplement pas la faire fonctionner avec Django 1.0, donc à la fin je suis revenue à la méthode de fermeture.
La méthode de fermeture est très soignée et la seule petite bizarrerie est que la définition de classe est imbriquée dans la vue ou dans une autre fonction. Je pense que le fait que cela me semble étrange est un blocage par rapport à mon expérience de programmation précédente et je pense que quelqu'un avec une formation dans des langages plus dynamiques ne ferait pas de cas!
la source
J'ai dû faire une chose similaire. Ceci est similaire à la
curry
solution:la source
sur la base de cette réponse, j'ai trouvé une solution plus claire:
Et lancez-le en vue comme
la source
Je suis un débutant ici, donc je ne peux pas ajouter de commentaire. J'espère que ce code fonctionnera aussi:
comme pour ajouter des paramètres supplémentaires au formset au
BaseFormSet
lieu de form.la source