web-dev-qa-db-fra.com

django admin - ajoute des champs de formulaire personnalisés qui ne font pas partie du modèle

J'ai un modèle enregistré sur le site d'administration. L'un de ses champs est une expression de chaîne longue. J'aimerais ajouter des champs de formulaire personnalisés à la page d'ajout/mise à jour de ce modèle dans l'administrateur. Je vais ensuite créer l'expression de chaîne longue en fonction de la valeur de ces champs et la sauvegarder dans le champ de modèle approprié.

Comment puis je faire ça?

UPDATE: Fondamentalement, je construis une expression mathématique ou une chaîne à partir de symboles, l'utilisateur choisit des symboles (ce sont les champs personnalisés qui ne font pas partie du modèle) et lorsqu'il clique sur enregistrer, je crée une représentation d'expression de chaîne à partir du liste des symboles et la stocker 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, mais uniquement de l'expression finale.

86
michalv82

Vous pouvez ajouter une classe ModelForm dans votre fichier admin.py ou dans un autre formulaire.py, puis déclarer vos champs supplémentaires à l'intérieur comme d'habitude. J'ai également donné un exemple d'utilisation de ces valeurs dans 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'administrateur, il suffit de:

  1. éditez votre fichier admin.py et définissez la propriété de formulaire de manière à faire référence au formulaire que vous avez créé ci-dessus
  2. inclure vos nouveaux champs dans votre déclaration de champs ou d'ensembles de champs

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.

143
Vishnu

Il est possible de le faire dans l’administrateur, mais il n’ya pas de solution simple. De même, je vous conseille de conserver la plupart des logiques d’entreprise dans vos modèles afin que vous ne dépendiez pas de Django Admin.

Peut-être que ce serait plus facile (et peut-être même mieux) si vous aviez deux champs distincts sur votre modèle. Ajoutez ensuite 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’administrateur, vous pouvez ajouter le combined_fields() sous forme de 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 souhaitez stocker le combined_fields Dans la base de données, vous pouvez également l'enregistrer lors de l'enregistrement du modèle:

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

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

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

Si vous souhaitez uniquement stocker le champ combiné sur 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 suis pas tout à fait sûr de savoir comment ça va marcher.

3
gitaarik

Django 2.1.1 La réponse principale m'a amené à mi-chemin à répondre à ma question. Cela 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 puisse entrer des données, puis lorsqu’une sauvegarde était effectuée, les données étaient traitées et le résultat placé dans un champ du modèle, puis sauvegardé. Alors que la réponse originale montrait comment obtenir la valeur du champ extra, elle ne montrait pas comment la sauvegarder au moins dans le modèle Django 2.1.1

Cela prend la valeur d'un champ personnalisé non lié, 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__"
3
MangoLassi