Question

J'espère mettre à jour de manière dynamique la classe Meta en ligne de ModelForm depuis mon écran. Bien que ce code semble mettre à jour la liste d'exclusion de la classe Meta, la sortie de as_p () , as_ul () , etc. ne reflète pas l'exclusion Meta mise à jour.

Je suppose alors que le code HTML est généré lorsque le ModelForm est créé et non lorsque le as _ * () est appelé. Existe-t-il un moyen de forcer la mise à jour du code HTML?

Est-ce même la meilleure façon de le faire? Je viens de supposer que cela devrait fonctionner.

Pensées?

from django.forms import ModelForm

from testprogram.online_bookings.models import Passenger

class PassengerInfoForm(ModelForm):

    def set_form_excludes(self, exclude_list):
        self.Meta.exclude = excludes_list

    class Meta:
        model = Passenger
        exclude = []
Était-ce utile?

La solution

La classe Meta est utilisée pour construire dynamiquement la définition du formulaire. Ainsi, au moment où vous avez créé l'occurrence de ModelForm, les champs non inclus dans l'exclusion ont déjà été ajoutés en tant qu'attributs du nouvel objet.

La façon habituelle de procéder consiste simplement à avoir plusieurs définitions de classe pour chaque liste d'exclusion possible. Mais si vous voulez que le formulaire soit dynamique, vous devez créer une définition de classe à la volée. Quelque chose comme:

def get_form(exclude_list):
    class MyForm(ModelForm):
        class Meta:
            model = Passenger
            exclude = exclude_list
    return MyForm

form_class = get_form(('field1', 'field2'))
form = form_class()

MISE À JOUR : je viens de revoir ce post et je pensais poster un moyen un peu plus idiomatique de gérer une classe dynamique:

def PassengerForm(exclude_list, *args, **kwargs):
    class MyPassengerForm(ModelForm):
        class Meta:
            model = Passenger
            exclude = exclude_list

        def __init__(self):
            super(MyPassengerForm, self).__init__(*args, **kwargs)

    return MyPassengerForm()

form = PassengerForm(('field1', 'field2'))

Autres conseils

Autre moyen:

class PassengerInfoForm(ModelForm):
    def __init__(self, *args, **kwargs):
        exclude_list=kwargs.pop('exclude_list', '')

        super(PassengerInfoForm, self).__init__(*args, **kwargs)

        for field in exclude_list:
            del self.fields[field]

    class Meta:
        model = Passenger

form = PassengerInfoForm(exclude_list=['field1', 'field2'])

Approche similaire, objectif quelque peu différent (ModelForm générique pour les modèles arbitraires):

from django.contrib.admin.widgets import AdminDateWidget
from django.forms import ModelForm
from django.db import models

def ModelFormFactory(some_model, *args, **kwargs):
    """
    Create a ModelForm for some_model
    """
    widdict = {}
    # set some widgets for special fields
    for field in some_model._meta.local_fields:
        if type(field) is models.DateField:
            widdict[field.name] = AdminDateWidget()

    class MyModelForm(ModelForm): # I use my personal BaseModelForm as parent
        class Meta:
            model = some_model
            widgets = widdict

    return MyModelForm(*args, **kwargs)

Utilisez modelform_factory ( doc ):

from django.forms.models import modelform_factory

from testprogram.online_bookings.models import Passenger

exclude = ('field1', 'field2')
CustomForm = modelform_factory(model=Passenger, exclude=exclude)  # generates ModelForm dynamically
custom_form = CustomForm(data=request.POST, ...)  # form instance
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top