Django: Faking a field in the admin interface?

后端 未结 4 2026
轻奢々
轻奢々 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)
    
    0 讨论(0)
  • 2021-01-30 19:09

    It's easy enough to get arbitrary data to show up in change list or make a field show up in the form: list_display arbitrarily takes either actual model properties, or methods defined on the model or the modeladmin, and you can subclass forms.ModelForm to add any field type you'd like to the change form.

    What's far more difficult/impossible is combining the two, i.e. having an arbitrary piece of data on the change list that you can edit in-place by specifying list_editable. Django seems to only accept a true model property that corresponds to a database field. (even using @property on the method in the model definition is not enough).

    Has anyone found a way to edit a field not actually present on the model right from the change list page?

    0 讨论(0)
  • 2021-01-30 19:10

    In the edit form, put the property name into readonly_fields (1.2 upwards only).

    In the changelist, put it into list_display.

    0 讨论(0)
  • 2021-01-30 19:18

    You can use the @property decorator in your model (Python >= 2.4):

    class Product(models.Model):
    
        @property
        def ranking(self):
            return 1
    

    "ranking" can then be used in list_display:

    class ProductAdmin(admin.ModelAdmin):
        list_display = ('ranking', 'asin', 'title')
    
    0 讨论(0)
提交回复
热议问题