142 votes

Ajouter des champs de formulaire personnalisés qui ne font pas partie du modèle (Django)

J'ai un modèle enregistré sur le site d'administration. L'un de ses champs est une longue expression de type chaîne. J'aimerais ajouter des champs de formulaire personnalisés aux pages d'ajout et de mise à jour de ce modèle dans l'administration. Sur la base des valeurs de ces champs, je construirai l'expression de longue chaîne et l'enregistrerai dans le champ du modèle concerné.

Comment puis-je le faire ?

Je construis une expression mathématique ou une expression de chaîne de caractères à partir de symboles. L'utilisateur choisit des symboles (il s'agit de champs personnalisés qui ne font pas partie du modèle) et lorsqu'il clique sur "Enregistrer", je crée une représentation de l'expression de chaîne à partir de la liste de symboles et je la stocke dans la base de données. Je ne veux pas que les symboles fassent partie du modèle et de la base de données, seulement l'expression finale.

185voto

Vishnu Points 1636

Soit dans votre admin.py ou dans un forms.py vous pouvez ajouter un ModelForm puis déclarez vos champs supplémentaires à l'intérieur de cette classe comme vous le feriez normalement. J'ai également donné un exemple de la façon dont vous pouvez utiliser ces valeurs dans les champs suivants form.save() :

from django import forms
from yourapp.models import YourModel

class YourModelForm(forms.ModelForm):

    extra_field = forms.CharField()

    def save(self, commit=True):
        extra_field = self.cleaned_data.get('extra_field', None)
        # ...do something with extra_field here...
        return super(YourModelForm, self).save(commit=commit)

    class Meta:
        model = YourModel

Pour que les champs supplémentaires apparaissent dans l'administration, il suffit d'en faire la demande :

  1. Modifiez votre admin.py et définissez la propriété du formulaire pour faire référence au formulaire que vous avez créé ci-dessus.
  2. Incluez vos nouveaux champs dans votre déclaration de champs ou de fieldsets.

Comme ça :

class YourModelAdmin(admin.ModelAdmin):

    form = YourModelForm

    fieldsets = (
        (None, {
            'fields': ('name', 'description', 'extra_field',),
        }),
    )

UPDATE :

Dans Django 1.8 vous devez ajouter fields = '__all__' à la métaclasse de YourModelForm .

49voto

rednaw Points 3856

Il est possible de le faire dans l'administration, mais il n'y a pas de moyen très direct de le faire. De plus, j'aimerais vous conseiller de garder la plupart de la logique d'entreprise dans vos modèles, afin de ne pas être dépendant de l'administration Django.

Peut-être que ce serait plus facile (et peut-être même mieux) si vous aviez les deux champs séparés sur votre modèle. Puis ajoutez une méthode sur votre modèle qui les combine.

Par exemple :

class MyModel(models.model):

    field1 = models.CharField(max_length=10)
    field2 = models.CharField(max_length=10)

    def combined_fields(self):
        return '{} {}'.format(self.field1, self.field2)

Ensuite, dans l'administration, vous pouvez ajouter le combined_fields() comme un champ en lecture seule :

class MyModelAdmin(models.ModelAdmin):

    list_display = ('field1', 'field2', 'combined_fields')
    readonly_fields = ('combined_fields',)

    def combined_fields(self, obj):
        return obj.combined_fields()

Si vous voulez stocker le combined_fields dans la base de données, vous pouvez également l'enregistrer lorsque vous enregistrez le modèle :

def save(self, *args, **kwargs):
    self.field3 = self.combined_fields()
    super(MyModel, self).save(*args, **kwargs)

10voto

MangoLassi Points 71

Django 2.1.1 La réponse primaire m'a permis de répondre à moitié à ma question. Elle ne m'a pas aidé à enregistrer le résultat dans un champ de mon modèle actuel. Dans mon cas, je voulais un champ de texte dans lequel un utilisateur pourrait entrer des données, puis, lors de l'enregistrement, les données seraient traitées et le résultat serait placé dans un champ du modèle et enregistré. Alors que la réponse originale montrait comment obtenir la valeur du champ supplémentaire, elle ne montrait pas comment la sauvegarder dans le modèle, du moins dans Django 2.1.1.

Cette opération prend la valeur d'un champ personnalisé non lié, la traite et l'enregistre dans mon champ de description réel :

class WidgetForm(forms.ModelForm):
    extra_field = forms.CharField(required=False)

    def processData(self, input):
        # example of error handling
        if False:
            raise forms.ValidationError('Processing failed!')

        return input + " has been processed"

    def save(self, commit=True):
        extra_field = self.cleaned_data.get('extra_field', None)

        # self.description = "my result" note that this does not work

        # Get the form instance so I can write to its fields
        instance = super(WidgetForm, self).save(commit=commit)

        # this writes the processed data to the description field
        instance.description = self.processData(extra_field)

        if commit:
            instance.save()

        return instance

    class Meta:
        model = Widget
        fields = "__all__"

4voto

Eyal Ch Points 186

Vous pouvez toujours créer un nouveau modèle d'administration, et faire ce dont vous avez besoin dans votre modèle d'administration. admin_view (remplacez l'URL ajoutée par l'administrateur dans votre admin_view ) :

url(r'^admin/mymodel/mymodel/add/$','admin_views.add_my_special_model')

3voto

rednaw Points 3856

Si vous souhaitez absolument ne stocker que le champ combiné dans le modèle et non les deux champs distincts, vous pouvez procéder comme suit :

Je n'ai jamais fait quelque chose comme ça, donc je ne sais pas vraiment comment ça va se passer.

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