Django管理员:如何格式化readonly字段? [英] Django admin: how to format readonly fields?

查看:943
本文介绍了Django管理员:如何格式化readonly字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模型, Director 与两个DateFields和两个子类(下面的代码)。我正在为每个Director创建一个管理页面,该页面显示相应的子类实例,而不是 Director instance;这个部分大部分是容易的(我为每个子类创建一个内联,给主模型管理器一个所有字段被排除的形式,并且只有主要的ModelAdmin只有从内联请求的formets有相应的实例 - 代码;有一个未解决的问题使用这种方法,我在下面注意到,但不是这个问题的重点)。

I have a model, Director with two DateFields, and two subclasses (code below). I am trying to create an admin page for each Director which shows the corresponding subclass instance, and not the Director instance; this part is mostly easy (I create an inline for each subclass, give the main ModelAdmin a form with all fields excluded, and have the main ModelAdmin only request formsets from the inlines which have a corresponding instance - the code; there is an unresolved issue with this approach, which I note below, but is not the focus of this question).

我遇到的问题是我想按摩显示的值其中一个显示在只读字段中,其中一个不是。处理是我想将一个魔术值( date(1,1,1))更改为字符串在公司上

The problem I have is that I want to massage the values displayed to the user, one of which is shown in a readonly field, one of which is not. The processing is that I want to change a magic value (date(1,1,1)) to the string "On incorporation".

只读字段中的日期不会以非常友好的解析格式呈现,我想减少对JavaScript的不必要依赖,所以我更喜欢服务器端解决方案。

Dates in readonly fields aren't rendered in a format very friendly to parsing, and I would like to reduce unnecessary dependence on javascript, so I would very much prefer a server-side solution.

下面的代码显示了我想要的表单,除了日期值根本没有按摩,保存时,即使没有错误,还有一个虚假的请更正错误消息,所有字段都保存正确。

The code below displays the forms as I want them, except that date values are not massaged at all, and when saving, there is a spurious "Please correct the error below" message, even though there are no errors, and all fields are saved correctly.

我的问题是:如何截取在页面上显示的值,在只读字段和表单字段中,并更改它们以显示我选择的字符串?

模型(至于材料):

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 子类,有一些小的更改,不应该是后果。额外的代码可以按照合理的请求显示,但我不想混淆不相关的代码。

I realise that there is an asymmetry between DirectorsCorporateInline and DirectorsIndividualInline; that is because I am testing on an instance with a DirectorsIndividual instance. The code above refers to model fields not shown in the models, because they are not material to the dates issue; it should be possible to render them immaterial for the spurious error issue without altering those fields (although I realise it is less helpful for that issue, I want to keep this question mostly focused on one issue). EnhancedAdmin is a ModelAdmin subclass with some minor alterations which shouldn't be of consequence. Extra code can be shown on reasoned request, but I don't want to confuse with irrelevant code.

为了完整性:我在python 2.7上使用django 1.3.1。 2。

For completeness: I am using django 1.3.1 on python 2.7.2.

推荐答案

定义您的 Director 类的成员函数你想要的readonly_field。

Define a member function of your Director class that renders the readonly_field as you want.

class Director(models.Model, Specializable):
    date_of_appointment = models.DateField()
    date_ceased_to_act = models.DateField(blank=True,null=True)
    def date_of_appointment_str(self):
        if self.date_of_appointment == datetime.date(1,1,1):
            return "On incorporation"
        else:
            return "%s" % (self.date_of_appointment) # format as you wish

然后只需将'date_of_appointment_str'添加到您的列表 readonly_fields 在管理员中。

and then just add 'date_of_appointment_str' to your list of readonly_fields in the admin.

编辑:我应该补充说,这是一个快速的解决方案。一个更强大的解决方案是将 models.DateField 子类化为 MyCustomDateField ,其行为类似于 DateField 除了当值为 date(1,1,1)时,它呈现为On Incorpor或用户保存On Incorpor它将值保存为 date(1,1,1)。这将确保您可以在此字段类型显示的任何地方重复使用此功能。但是,如果它只显示在一个地方;这可能是过度的。

I should add that this is one quick solution. A more robust solution is to subclass models.DateField into a MyCustomDateField that acts like a DateField except that when the value is date(1,1,1) it renders as "On incorporation" or when a user saves "On incorporation" it saves the value as date(1,1,1). This would ensure that you can reuse this functionality everywhere this field type shows up. However, if it only shows up in one place; this may be overkill.

您需要类似的东西(这是未经测试的;您可能需要另外更改您的表单 DateField 和/或其他东西;例如,如果您使用django-south,您将不得不添加自定义内省规则。)

You'd need something like (this is untested; you may need to additionally alter your the forms DateField and/or other things; e.g., if you use django-south you'll have to add custom introspection rules).

class MyCustomDateField(models.DateField):
    date_111_str = 'On incorporation'
    def value_to_string(self, obj):
        val = self._get_val_from_obj(obj)
        if val is None:
            data = ''
        elif val.year == val.day == val.month == 1:
            data = date_111_str
        else:
            data = datetime_safe.new_date(val).strftime("%Y-%m-%d")
        return data
    def get_prep_value(self, value):
        if value == date_111_str:
            value = datetime.date(1,1,1)
        return super(MyCustomDateField,self).get_prep_value(self, value)

这篇关于Django管理员:如何格式化readonly字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆