I have a model, Director
with two DateFields and two subclasses (code below). I am trying to create an admin page for each director that shows the corresponding instance of the subclass, not the Director
instance; this part is basically simple (I create a built-in for each subclass, provide the main ModelAdmin form with all fields excluded and get only the main ModelAdmin modules for queries from inline strings that have the corresponding instance - the code, there is an unresolved problem with this approach, which I note below, but not the focus of this question).
The problem is that I want to massage the values displayed to the user, one of which is shown in the readonly field, one of which is not. The processing is that I want to change the magic value ( date(1,1,1)
) to the string "On incorporation"
.
Dates in readonly fields are not displayed in a format that is very convenient for parsing, and I would like to reduce unnecessary javascript dependency, so I would really prefer a server-side solution.
The code below shows the forms that I need, except that the date values are not massed at all, and when saved, the false message "Please correct the error below" appears even if there are no errors and all fields are saved correctly.
My question is: how to intercept the values displayed on the page, both in the readonly fields and in the form fields and change them to display a line of my choice?
Models (based on materials):
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
Admin Code:
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 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))
I understand that there is an asymmetry between DirectorsCorporateInline
and DirectorsIndividualInline
; because I'm testing an instance with a DirectorsIndividual
instance. The code above refers to model fields not shown in the models, since they are not essential for the release of dates; it should be possible to make them inconsequential for a false error without changing these fields (although I understand that this is less useful for this problem, I want this question to focus mainly on one problem). EnhancedAdmin
is a subclass of ModelAdmin
with some minor changes that shouldn't matter. Additional code may be shown by reasoned request, but I do not want to be confused with irrelevant code.
For completeness: I am using django 1.3.1 on python 2.7.2.