Django: Faking a field in the admin interface?

后端 未结 4 2027
轻奢々
轻奢々 2021-01-30 19:00

I have a model, Foo. It has several database properties, and several properties that are calculated based on a combination of factors. I would like to present these

4条回答
  •  无人及你
    2021-01-30 19:06

    I would suggest you subclass a modelform for Foo (FooAdminForm) to add your own fields not backed by the database. Your custom validation can reside in the clean_* methods of ModelForm.

    Inside the save_model method of FooAdmin you get the request, an instance of Foo and the form data, so you could do all processing of the data before/after saving the instance.

    Here is an example for a model with a custom form registered with 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)
    

    Providing initial values for custom fields based on instance data

    (I'm not sure if this is the best solution, but it should work.)

    When a modelform for a existing model instance in the database is constructed, it gets passed this instance. So in FooAdminForm's __init__ one can change the fields attributes based on instance data.

        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)
    

提交回复
热议问题