70 votes

Django formes, l'héritage et l'ordre des champs de formulaire

Je suis l'aide de Django formes dans mon site web et souhaitez contrôler l'ordre des champs.

Voici comment je définis mes formulaires:

class edit_form(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)


class create_form(edit_form):
    name = forms.CharField()

Le nom est immuable et ne doivent être énumérées lorsque l'entité est créée. J'ai utiliser l'héritage pour ajouter de la cohérence et de la SEC principes. Ce qui se passe qui n'est pas fausse, en fait totalement prévu, c'est que le champ nom de la liste dans la vue/html, mais je voudrais le nom de domaine pour être au top de résumé et une description. Je me rends compte que je pouvais facilement le fixer en copiant le résumé et la description dans create_form et de perdre l'héritage, mais j'aimerais savoir si cela est possible.

Pourquoi? Imaginez que vous avez 100 champs dans edit_form et ont pour ajouter 10 les champs de la table dans create_form - la copie et le maintien de ces deux formes ne serait pas l'air si sexy alors. (C'est pas mon cas, je suis juste un exemple)

Alors, comment puis-je remplacer ce comportement?

Edit:

Apparemment, il n'y a pas de bonne façon de le faire sans passer par le méchant hacks (tripoter .champ d'attribut). L' .champ attribut est un SortedDict (l'un de Django structures de données internes) qui ne fournit pas de toute façon de réorganiser la clé:des paires de valeurs. Il n'est toutefois fournir un moyen de les insérer à un indice donné, mais qui permettrait de déplacer les éléments de la classe des membres et dans le constructeur. Cette méthode pourrait fonctionner, mais rendre le code moins lisible. La seule autre façon je vois ajustement est de modifier le cadre lui-même qui l'est moins-que-optimale dans la plupart des situations.

En bref, le code pourrait devenir quelque chose comme ceci:

class edit_form(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)


class create_form(edit_form):
    def __init__(self,*args,**kwargs):
        forms.Form.__init__(self,*args,**kwargs)

        self.fields.insert(0,'name',forms.CharField())

Que shut me up :)

107voto

Selene Points 1531

J'ai eu ce même problème et j'ai trouvé une autre technique pour la réorganisation des champs dans la Django livre de cuisine:

class EditForm(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)


class CreateForm(EditForm):
    name = forms.CharField()

    def __init__(self, *args, **kwargs):
        super(CreateForm, self).__init__(*args, **kwargs)
        self.fields.keyOrder = ['name', 'summary', 'description']

12voto

Joshua Points 331

J'ai utilisé la solution posté par Séléné, mais trouve qu'elle a enlevé tous les champs qui n'étaient pas affectés à keyOrder. Le formulaire que je suis sous-classement a beaucoup de champs afin que cela ne fonctionnait pas très bien pour moi. J'ai codé cette fonction pour résoudre le problème à l'aide de akaihola réponse, mais si vous voulez qu'il fonctionne comme Selene tout ce que vous devez faire est de mettre en throw_away de True.

def order_fields(form, field_list, throw_away=False):
    """
    Accepts a form and a list of dictionary keys which map to the
    form's fields. After running the form's fields list will begin
    with the fields in field_list. If throw_away is set to true only
    the fields in the field_list will remain in the form.

    example use:
    field_list = ['first_name', 'last_name']
    order_fields(self, field_list)
    """
    if throw_away:
        form.fields.keyOrder = field_list
    else:
        for field in field_list[::-1]:
            form.fields.insert(0, field, form.fields.pop(field))

C'est la façon dont je l'utilise dans mon code:

class NestableCommentForm(ExtendedCommentSecurityForm):
    # TODO: Have min and max length be determined through settings.
    comment = forms.CharField(widget=forms.Textarea, max_length=100)
    parent_id = forms.IntegerField(widget=forms.HiddenInput, required=False)

    def __init__(self, *args, **kwargs):
        super(NestableCommentForm, self).__init__(*args, **kwargs)
        order_fields(self, ['comment', 'captcha'])

10voto

Ted Points 1886

Il semble que, à un certain point, la structure sous-jacente de l'ordre des champs a été modifié à partir d'un django spécifique SordedDict d'un standard python OrderedDict

Ainsi, dans la 1.7, j'ai eu à faire ce qui suit:

from collections import OrderedDict

class MyForm(forms.Form):

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        original_fields = self.fields
        new_order = OrderedDict()
        for key in ['first', 'second', ... 'last']:
            new_order[key] = original_fields[key]
        self.fields = new_order

Je suis sûr que quelqu'un pourrait golf que dans deux ou trois lignes, mais pour S. O. fins je pense montrant clairement comment il fonctionne, c'est mieux que cleaver.

7voto

Jan Pöschko Points 2492

Vous pouvez également créer un décorateur à l'ordre des champs (inspiré par Josué de la solution):

def order_fields(*field_list):
    def decorator(form):
        original_init = form.__init__
        def init(self, *args, **kwargs):
            original_init(self, *args, **kwargs)        
            for field in field_list[::-1]:
                self.fields.insert(0, field, self.fields.pop(field))
        form.__init__ = init
        return form            
    return decorator

Cela permettra d'assurer que tous les champs transmis à la décoratrice venir en premier. Vous pouvez l'utiliser comme ceci:

@order_fields('name')
class CreateForm(EditForm):
    name = forms.CharField()

3voto

Alex Martelli Points 330805

Voir les notes en cela DONC, la question sur la façon de Django reinhardt, les internes de garder une trace de l'ordre des champs, et les réponses comprennent des suggestions sur la façon de "réorganiser" les champs à votre convenance (en fin de compte, ça revient à jouer avec le .fields d'attribut).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X