Django admin: как форматировать поля readonly?

У меня есть модель, Director с двумя DateFields, и двумя подклассами (код ниже). Я пытаюсь создать страницу администратора для каждого Director, которая показывает экземпляр соответствующего подкласса, а не экземпляр Director; эта часть в основном проста (я создаю инлайн для каждого подкласса, даю главному ModelAdmin форму с исключенными полями, и заставляю главного ModelAdmin запрашивать наборы форм только из тех инлайнов, которые имеют соответствующий экземпляр - код; есть нерешенная проблема с этим подходом, которую я отмечаю ниже, но она не является основной темой этого вопроса).

Проблема, с которой я столкнулся, заключается в том, что я хочу изменить значения, отображаемые пользователю, одно из которых отображается в поле readonly, а другое - нет. Обработка заключается в том, что я хочу изменить магическое значение (date(1,1,1)) на строку "On incorporation".

Даты в полях, доступных для чтения, не отображаются в формате, удобном для разбора, и я хотел бы уменьшить ненужную зависимость от javascript, поэтому я бы очень предпочел решение на стороне сервера.

Код ниже отображает формы так, как я хочу, за исключением того, что значения даты не обрабатываются вообще, и при сохранении появляется надуманное сообщение "Please correct the error below", хотя ошибок нет, и все поля сохранены правильно.

Мой вопрос: как мне перехватить значения, которые будут выводиться на страницу, как в полях readonly, так и в полях формы, и изменить их так, чтобы они отображали нужную мне строку?

Модели (пока материальные):

class Director(models.Model, Specializable):
    date_of_appointment = models.DateField()
    date_ceased_to_act = models.DateField(blank=True,null=True)

class DirectorsIndividual(Director):
     pass

class DirectorsCorporate(Director):
     pass

Код администратора:

class DirectorAdmin(EnhancedAdmin):

    fields = ()

##    def formfield_for_dbfield(self, db_field, **kwargs):
##        return None

    def queryset(self, request):
        """ Directors for all companies which are incorporated by the current user's organisation """
        individual = Individual.for_user(request.user)
        return Director.objects.filter(company__incorporation_ticket__ordered_by__in = Organisation.all_organisations_for_which_individual_authorised_to_incorporate(individual))

    class form(forms.ModelForm):
        # have this return no html - that way only inlines are shown
        class Meta:
            fields = ()
            pass

        def is_valid(self):
            self._errors = {}
            return True

    class DirectorsIndividualInline(admin.StackedInline):
        model = DirectorsIndividual
        fk_name = 'director_ptr'
        extra = 0
        readonly_fields = ('deferred_on','company','date_of_appointment',)
        can_delete = False

        def get_readonly_fields(self, request, obj=None):
            if obj and obj.company and not obj.company.is_submitted(): return self.readonly_fields # allow editing of fields listed in else
            else:
                return itertools.chain(self.readonly_fields, ('individual', 'is_secretary'))

        def has_delete_permission(self, request, obj=None):
            return obj and ((obj.company and not obj.company.is_submitted()) or not obj.company)

        class form(forms.ModelForm):
            def __init__(self, *args, **kwargs):
                super(forms.ModelForm, self).__init__(*args, **kwargs)
                self.fields['surrogate_for'].required = False
                self.fields['representative_for'].required = False
                if self.instance:
                    obj = self.instance
                    for field in (f for f in type(obj)._meta.fields if type(f) == fields.DateField):
                        val = field.value_from_object(obj)
                        assert (type(val) in (datetime.date, type(None),))
                        # assert field.name != 'date_of_appointment'
                        if val == inc_consts.EARLIEST_DATE:
                            self.initial[field.name] = "On incorporation"

            def is_valid(self):
                self._errors = {}
                return True

    class DirectorsCorporateInline(admin.StackedInline):

        model = DirectorsCorporate
        fk_name = 'director_ptr'
        extra = 0
        can_delete = False

        class form(forms.ModelForm):
            def __init__(self, *args, **kwargs):
                super(forms.ModelForm, self).__init__(*args, **kwargs)
                if True:
                    for k in self.fields:
                        self.fields[k].required = False

            def is_valid(self):
                self._errors = {}
                return True


    inlines = (DirectorsIndividualInline,DirectorsCorporateInline)

    def get_inlines(self, request, obj=None):
        return (inline for inline in (self.inline_instances)
                if inline.model.objects.filter(**{(inline.fk_name or self.model._meta.object_name.lower()) : obj }))

    def get_formsets(self, request, obj=None):
        """ only return formset for inlines for which there exists an object """
        return (inline.get_formset(request, obj) for inline in self.get_inlines(request, obj))

Я понимаю, что есть асимметрия между DirectorsCorporateInline и DirectorsIndividualInline; это потому, что я тестирую на экземпляре с экземпляром DirectorsIndividual. Код выше относится к полям модели, не отображаемым в моделях, потому что они не существенны для проблемы дат; должно быть возможно сделать их несущественными для проблемы ложной ошибки, не изменяя эти поля (хотя я понимаю, что это менее полезно для этой проблемы, я хочу, чтобы этот вопрос был сосредоточен на одной проблеме). EnhancedAdmin является подклассом ModelAdmin с некоторыми незначительными изменениями, которые не должны иметь значения. Дополнительный код может быть показан по аргументированному запросу, но я не хочу путать с нерелевантным кодом.

Для полноты картины: Я использую django 1.3.1 на python 2.7.2.

9
задан Marcin 3 January 2012 в 18:20
поделиться