django admin - додайте спеціальні поля форм, які не входять до моделі


106

У мене зареєстрована модель на сайті адміністратора. Одне з його полів - це вираження довгих рядків. Я хотів би додати спеціальні поля форми на сторінку додавання / оновлення цієї моделі в адміністраторі, що на основі значень цих полів я буду будувати вираз довгих рядків і зберігати його у відповідному полі моделі.

Як я можу це зробити?

ОНОВЛЕННЯ: В основному те, що я роблю, це будувати математичне або рядкове вираження з символів, користувач вибирає символи (це користувацькі поля, які не є частиною моделі), і коли він натискає кнопку "Зберегти", я створюю представлення виразного рядка з список символів та збережіть їх у БД. Я не хочу, щоб символи були частиною моделі та БД, лише завершальним виразом.

Відповіді:


156

Або у своєму admin.py, або в окремому form.py ви можете додати клас ModelForm, а потім оголосити зайві поля всередині, як зазвичай. Я також наводив приклад того, як ви можете використовувати ці значення у 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

Щоб додаткові поля відображалися в адміністраторі просто:

  1. відредагуйте admin.py і встановіть властивість форми відповідно до форми, яку ви створили вище
  2. включіть у поле ваші нові поля або декларацію наборів полів

Подобається це:

class YourModelAdmin(admin.ModelAdmin):

    form = YourModelForm

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

ОНОВЛЕННЯ: У django 1.8 вам потрібно додати fields = '__all__'до метакласу YourModelForm.


2
Так, я дуже хочу дізнатися причину
Vishnu

13
Ви повинні додати fields = '__all__'до свого Metaкласу, інакше django скаржиться:Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is deprecated
IsaacKleiner

1
@sthzg, Тому що це неправильно. Це дає мені помилку:YourModelAdmin.list_display[0], 'extra_field' is not a callable or an attribute of 'YourModelAdmin' or found in the model 'YourModel'.
Cerin

7
Якщо з якихось причин ви отримаєте запит AttributeError: Unable to lookup "extra_field"..., спробуйте додати labelдо extra_fieldвизначення. Здається, що django намагається «відгадати» мітку для неї, переглянувши Modelта визначаючи ModelAdminтаке визначення атрибута.
alxs

1
Це прекрасно спрацювало, якщо extra_field - це CharField (). Якщо це приховане поле, хоча [У Django 1.11], генерується помилка Unknown field(s) (extra_field) specified for YourModel. Check fields/fieldsets/exclude attributes of class YourModelAdmin.. Вирішення цього питанняextra_field = forms.CharField(widget=forms.HiddenInput())
какома

35

Це можна зробити в адміністраторі, але це не дуже простий шлях до цього. Також я хотів би порадити зберігати більшість бізнес-логіки у ваших моделях, тому ви не будете залежні від адміністратора Django.

Можливо, було б простіше (а може бути навіть краще), якщо у вас є дві окремі поля на вашій моделі. Потім додайте у вашу модель метод, який поєднує їх.

Наприклад:

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)

Тоді в адміністраторі ви можете додати поле combined_fields()як лише для читання:

class MyModelAdmin(models.ModelAdmin):

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

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

Якщо ви хочете зберегти combined_fieldsв базі даних, ви також можете зберегти її під час збереження моделі:

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

4
Дякую за відповідь, але це не те, що я шукаю. Я не хочу, щоб спеціальні поля зберігалися в БД, лише обчислена рядок. В основному те, що я роблю, це будувати математичне або рядкове вираження з символів, користувач вибирає символи (це користувацькі поля, які не є частиною моделі), і коли він натискає кнопку "Зберегти", я створюю подання рядкового вираження зі списку символів і зберігати їх у БД.
michalv82

@ michalv82 Ви також можете зберегти його до бази даних save()методом моделі , перевірте оновлення моєї відповіді.
gitaarik

1
ще раз дякую, але проблема полягає в тому, що я не хочу зберігати поля, що поєднують остаточне поле (тобто символи), я просто хочу, щоб остаточний рядок був збережений
michalv82

Чи є проблема зберегти 2 поля? Можливо, це стане у нагоді, якщо ви хочете знати, як генерується комбіноване поле.
gitaarik

6
ще раз дякую, але це не 2 поля, можливо, буде більше. Знову я не хочу зберігати їх у БД, тому це рішення не може працювати для мене.
michalv82

5

Django 2.1.1 Основна відповідь отримала мене на півдорозі, щоб відповісти на моє запитання. Це не допомогло мені зберегти результат у полі в моїй фактичній моделі. У моєму випадку я хотів текстове поле, щоб користувач міг вводити дані, тоді, коли відбулося збереження, дані оброблялися б, а результат ставився у поле в моделі та зберігався. Хоча в оригінальній відповіді було показано, як отримати значення з додаткового поля, воно не показало, як зберегти його назад до моделі принаймні у Django 2.1.1

Це приймає значення з незв'язаного користувальницького поля, обробляє і зберігає його в моєму реальному полі опису:

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__"

4

ви завжди можете створити новий шаблон адміністратора і зробити все, що вам потрібно в адміністраторі перегляду (замініть адміністратор, додайте URL до свого адміністратора):

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

3

Якщо ви абсолютно хочете зберігати лише комбіноване поле на моделі, а не два окремих поля, ви можете зробити щось подібне:

Я ніколи не робив щось подібне, тому я не зовсім впевнений, як це вийде.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.