Django admin - добавление полей пользовательской формы, которые не являются частью модели
У меня есть модель, зарегистрированная на сайте администратора. Одно из его полей - длинное строковое выражение. Я хотел бы добавить пользовательские поля формы на страницу добавления/обновления этой модели в админе, которая на основе этих значений полей построит длинное строковое выражение и сохранит его в соответствующем поле модели.
Как я могу это сделать?
UPDATE:
В основном то, что я делаю, это построение математического или строкового выражения из символов, пользователь выбирает символы (это настраиваемые поля, которые не являются частью модели), и когда он нажимает на сохранение, я создаю представление строкового выражения из списка символов и сохранить их в БД. Я не хочу, чтобы символы были частью модели и DB, а только окончательное выражение.
Ответы
Ответ 1
Либо в файле admin.py, либо в отдельном файле forms.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
Чтобы дополнительные поля появились в админке, просто:
- отредактируйте ваш admin.py и установите свойство формы для ссылки на форму, которую вы создали выше
- включите ваши новые поля в декларацию полей или наборов полей
Как это:
class YourModelAdmin(admin.ModelAdmin):
form = YourModelForm
fieldsets = (
(None, {
'fields': ('name', 'description', 'extra_field',),
}),
)
ОБНОВЛЕНИЕ: в django 1.8 вам нужно добавить fields = '__all__'
в метакласс YourModelForm.
Ответ 2
Это возможно сделать в админе, но нет очень простого пути к нему. Кроме того, я хотел бы посоветовать сохранить большинство бизнес-логики в ваших моделях, поэтому вы не будете зависеть от администратора 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)
Затем в admin вы можете добавить 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)
Ответ 3
вы всегда можете создать новый шаблон администратора и сделать то, что вам нужно в вашем admin_view (переопределить админ, добавляющий url для вашего admin_view):
url(r'^admin/mymodel/mymodel/add/$' , 'admin_views.add_my_special_model')
Ответ 4
Если вы абсолютно хотите хранить комбинированное поле на модели, а не два отдельных поля, вы можете сделать что-то вроде этого:
Я никогда не делал ничего подобного, поэтому я не совсем уверен, как это получится.
Ответ 5
Джанго 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__"
Ответ 6
Сначала добавьте поле в форму
class CreateForm(forms.ModelForm):
extra_field = forms.CharField(label = 'extra_field', required = False)
Теперь при очистке данных вам нужно извлечь дополнительное поле из self.data, а не self.cleaned_data.
Исправить:
self.data.get('extra_field')
Неправильно
self.cleaned_data.get('extra_field')