2010-02-09 10 views
3

Je suis sur le point de démarrer un grand projet Django au travail. Et les principales caractéristiques sont la gestion des formulaires. Il va y avoir beaucoup de formulaires que les utilisateurs de l'application vont utiliser. Et une exigence est qu'il devrait être possible de modifier les formulaires dans l'interface d'administration de l'application.Exigences de formes dynamiques dans Django

En d'autres termes, il n'est pas nécessaire d'ajouter/de supprimer des champs de formulaire. Mais il devrait être possible d'éditer les attributs de champ de formulaire. Par exemple, changez les champs requis et autres.

Tout le monde a de bonnes solutions pour ce faire. Im pensant que je pourrais avoir à sous-classer les champs que je veux être dynamique et faire quelque chose là-bas. Je suppose que tous les champs des modèles doivent avoir "blank = True/null = True" et d'autres comment ajouter des méta-informations dans un modèle séparé (?) Sur le modèle qui déclare que les champs sont obligatoires. Et puis utilisez cette information lorsque les formulaires sont affichés et validés. Avant que je commence à faire ceci je voudrais vraiment une certaine entrée dans la façon de concevoir une telle solution, n'importe qui a eu des idées sur la façon dont cela devrait être fait?


Après plus de recherche, j'ai appris que vous pourriez faire a'lot avec des fonctions d'usine qui retourne le formulaire avec les attributs donnés définis. Donc, il semble que le problème n'est pas si difficile à résoudre.

Je voudrais créer une fonction qui retourne un formulaire avec le bon jeu d'attributs/champs. Mais la partie pour laquelle je n'ai pas trouvé de bonne solution est de savoir comment gérer cela dans l'interface d'administration. Je pense que je ferais un db.Model qui stocke des informations sur d'autres champs de modèles. Où je peux définir ce qui est requis et tel.

Ensuite, dans la fonction qui retourne le formulaire, passez ce modèle et renvoyez un formulaire avec les bons attributs. Mais comment faire ce modèle (qui devrait refléter d'autres champs de modèles) dans le bon sens?

Répondre

2

Vous devez utiliser certains modèles pour cela. Pour chaque formulaire qui peut être personnalisé de cette manière, une nouvelle entrée de base de données doit être créée. Je suppose, il devrait ressembler à ceci:

class FormSettings(Model): 
    form = CharField(..) 

class FormAttrib(Model): 
    form_settings = ForeignKey(FormSettings) 
    field = CharField(..) 
    attrib_name=CharField(..) 
    attrib_value=CharField(..) 

Dans FormSettings.form vous devez stocker une adresse de la forme, comme par exemple. et quand le formulaire est construit (dans init), il devrait rechercher une entrée dans db et utiliser attribs, qui ont été décrits pour cela. Vous pouvez lui faire créer des entrées db facilement, si vous utilisez votre propre métaclasse pour vos formulaires et l'enregistrez dans la base de données (créez l'entrée FormSettings appropriée), quand une classe est créée. Cela se fera une fois au début du processus, ce qui ne devrait pas être si grave.

J'espère que ça aide un peu. Si vous avez d'autres questions, je serai heureux de vous aider :-) J'aime les appareils non standard de django :-) C'est là tout le plaisir commence :-)

EDIT:

OK , disons, que vous voulez que vous ayez de la nourriture app et formez FavouriteFoodForm avec le champ food_name. Vous stockez dans la base de données dans formsettings table comme food.FavouriteFoodForm et ajoutez un paramètre d'attribut: field = 'food_name', attrib_name = 'required', attribute_value = 'True' (ce n'est pas parfait, mais ce n'est pas si mal ').

Non dans FavouriteFoddForm vous recherchez les paramètres dans la base de données, de sorte que vous faites:

settings = FormSettings.objects.get(form=app_name + self.__class__.name) 

et vous itérer sur les paramètres

for setting in settings.formattrib_set(): 

et ici simple appel exec et définir l'attribut approprié:

exec("getattr(self, settings.field)[attrib_name] = %s" % attrib_value) 

Cela doit définir les attributs sur required = True.

+0

Merci pour la réponse, mais j'ai eu quelques problèmes à comprendre ce que vous dites. Pourriez-vous écrire une description encore plus détaillée de votre solution? Comme je l'ai mentionné dans la dernière partie de la question, j'ai trouvé beaucoup d'informations utiles dans cet article sur b-list.org http://www.b-list.org/weblog/2008/nov/09/dynamic -forms/ On dirait que ça va aider beaucoup. Mais encore faut s'attaquer à la façon de stocker les paramètres de formulaire en DB. – espenhogbakk

+0

Ok, ça me donne beaucoup plus de sens. On dirait une solution qui fonctionnerait. Mais pourrait être fait plus élégamment? Est-il possible de faire une introspection de modèle ou quelque chose qui rende le formulaire FormAttrib et FormSettings? – espenhogbakk

+0

Vous voulez dire forme introspection, non? Oui, cela peut être fait, mais je crois, que c'est un peu trop de décrire ici;) Essayez de lire sur les métaclasses - Je crois que c'est le point, où vous en avez besoin, bien que certains python gourou dit, que dans 99% des cas vous n'en avez pas besoin. Il est préférable de lire le code de ModelForm, qui analyse les modèles pour construire les champs appropriés. Vous aurez besoin de quelque chose de similaire, mais pour Form. Fondamentalement, vous allez le faire autrement et avoir FormModel ;-) – gruszczy

2

Ce n'est pas une réponse exacte à votre problème, mais j'ai fait quelque chose de similaire que je pensais être utile pour vous. J'ai créé un formulaire entièrement personnalisable, afin que le formulaire puisse être personnalisé par les utilisateurs finaux.

J'ai fini avec 2 modèles, un BuiltForm et un BuiltFormField:

class BuiltForm(models.Model): 
    name = models.CharField(max_length=32) 
    def form(self, data=None, initial=None): 
     form = BuiltFormGenericForm(data, initial=initial) 
     form.addBuiltFormFields(BuiltFormField.objects.filter(builtform=self, disabled=0)) 
     return form    

class BuiltFormField(models.Model): 
    builtform = models.ForeignKey(BuiltForm) 
    type = models.CharField(max_length=32, choices=ALL_FIELD_TYPES) 
    label = models.CharField(max_length=32) 
    fieldname = models.CharField(max_length=32) 
    helptext = models.CharField(max_length=256, blank=True) 
    required = models.BooleanField(default=False) 
    sort_order = models.IntegerField(default=0) 
    disabled = models.BooleanField(default=False) 
    options = models.TextField(blank=True) 
    def field(self): 
     field = ALL_FIELD_MAPS.get(self.type) 
     ## Build out the field, supplying choices, `required`, etc. 

Il y a deux choses qui sont anormales. ALL_FIELD_TYPES est une carte des types de champs autorisés dans le formulaire. Ceci est utilisé en conjonction avec un dict() pour discerner quelle classe (CharField, EmailField, ChoiceField, etc.) doit être utilisée pour ce champ. options est également une pickle d liste d'options pour une utilisation ultérieure dans un ChoiceField. Cela m'a permis de créer une liste arbitraire d'options sans un appel distinct à la base de données.

L'autre élément majeur est une classe personnalisée Form qui se permet d'être remplie avec les champs d'un BuiltForm. Le mien ressemble à ceci:

class BuiltFormGenericForm(forms.Form): 
    built_form_fields = {} 
    builtform = None 
    def addBuiltFormFields(self, fields): 
     for field in fields: 
      self.fields[field.label] = field.field() 
      self.built_form_fields[field.pk] = field 
    def is_valid(self): 
     # Do validation here. My code for this is pretty big because of custom fields 
     # and calculations that I have to squeeze in. 

Les objets BuiltFormField ne sont pas conçus pour être créé via l'interface d'administration, mais plutôt par une coutume dont une avec une tonne de JavaScript pour elle convivial faire, mais vous pouvez certainement exposer parties du modèle BuiltFormField dans l'interface d'administration pour les mettre à jour.

Espérons que cela vous aidera à élaborer un modèle pour vos formulaires.

+0

Genius, beaucoup de bon code et consepts ici. C'est agréable de voir des choses comme cela est possible.Sorte une solution proposée simular à @gruszczy. – espenhogbakk