Django: Подделка поля в интерфейсе администратора?

У меня есть модель, Foo. Он имеет несколько свойств базы данных и несколько свойств, которые рассчитываются на основе комбинации факторов. Я хотел бы представить эти рассчитанные свойства пользователю, как если бы они были свойствами базы данных. (Факторы поддержки будут изменены, чтобы отражать пользовательский ввод.) Есть ли способ сделать это с помощью интерфейса администратора Django?

Ответы

Ответ 1

Я бы предложил вам подкласс modelform для Foo (FooAdminForm), чтобы добавить ваши собственные поля, не поддерживаемые базой данных. Ваша пользовательская проверка может находиться в методах clean_* ModelForm.

Внутри метода save_model FooAdmin вы получите запрос, экземпляр Foo и данные формы, чтобы вы могли выполнять всю обработку данных до/после сохранения экземпляра.

Вот пример модели с пользовательской формой, зарегистрированной в django admin:

from django import forms
from django.db import models
from django.contrib import admin


class Foo(models.Model):
    name = models.CharField(max_length=30)


class FooAdminForm(forms.ModelForm):
    # custom field not backed by database
    calculated = forms.IntegerField()

    class Meta:
        model = Foo 


class FooAdmin(admin.ModelAdmin):
    # use the custom form instead of a generic modelform
    form = FooAdminForm

    # your own processing
    def save_model(self, request, obj, form, change):
        # for example:
        obj.name = 'Foo #%d' % form.cleaned_data['calculated'] 
        obj.save()


admin.site.register(Foo, FooAdmin)

Предоставление начальных значений для настраиваемых полей на основе данных экземпляра

(Я не уверен, что это лучшее решение, но оно должно работать.)

Когда модель модели для существующего экземпляра модели в базе данных сконструирована, он получает этот экземпляр. Таким образом, в FooAdminForm __init__ можно изменить атрибуты полей на основе данных экземпляра.

    def __init__(self, *args, **kwargs):
        # only change attributes if an instance is passed            
        instance = kwargs.get('instance')
        if instance:
            self.base_fields['calculated'].initial = (instance.bar == 42)
        forms.ModelForm.__init__(self, *args, **kwargs)

Ответ 2

Достаточно легко получить произвольные данные для отображения в списке изменений или создать поле в форме: list_display произвольно принимает либо фактические свойства модели, либо методы, определенные на модели или modeladmin, и вы можете подклассы forms.ModelForm, чтобы добавить любой тип поля, который вы хотите изменить.

Что намного сложнее/невозможнее объединить два, то есть иметь произвольную часть данных в списке изменений, которую вы можете редактировать на месте, указав list_editable. Кажется, что Django принимает только истинное свойство модели, соответствующее поле базы данных. (даже при использовании @property для метода в определении модели недостаточно).

Кто-нибудь нашел способ редактировать поле, которое фактически не присутствует на модели, прямо со страницы списка изменений?

Ответ 3

В форме редактирования поместите имя свойства в readonly_fields (только 1.2 вверх).

В списке изменений переместите его в list_display.

Ответ 4

Вы можете использовать декоратор @property в своей модели (Python >= 2.4):

class Product(models.Model):

    @property
    def ranking(self):
        return 1

"ранжирование" может затем использоваться в list_display:

class ProductAdmin(admin.ModelAdmin):
    list_display = ('ranking', 'asin', 'title')