简体   繁体   中英

Creating a display-only (non-editable) Django admin field

Is it possible to build a custom model field/widget combination which displays a value but never writes anything back to the database? I would use this widget exclusively in the admin's forms.

I wrote my own field, which overwrites the formfield() method to declare its own widget class. It displays just fine, but as soon as the 'Save' button is clicked in the admin, I'm getting a validation error:

This field is required.

That makes sense, considering that my widget didn't render out a form field. However, what I'd like to do is basically remove this field from the update process: whenever used in the admin, it just shouldn't be mentioned in the SQL UPDATE at all.

Is that possible?

Here's a sketch of the code I have so far:

class MyWidget(Widget):
    def render(self, name, value, attrs=None):
        if value is None:
            value = ""
        else:
            # pretty print the contents of value here
            return '<table>' + ''.join(rows) + '</table>'

class MyField(JSONField):
    def __init__(self, *args, **kwargs):
        kwargs['null'] = False
        kwargs['default'] = list
        super(MyField, self).__init__(*args, **kwargs)

    def formfield(self, **kwargs):
        defaults = {
            'form_class': JSONFormField,
            'widget': MyWidget,
        }
        defaults.update(**kwargs)
        return super(MyField, self).formfield(**defaults)

UPDATE 1: The use case is that the field represents an audit log. Internally, it will be written to regularly. The admin however never needs to write to it, it only has to render it out in a very readable format.

I'm not using any other ModelForms in the application, so the admin is the only form-user. I don't want to implement the behavior on the admin classes themselves, because this field will be reused across various models and is always supposed to behave the same way.

There are multiple ways to create a read-only field in the admin pages. Your requirements on the database storage are a bit fuzzy so I go through the options.

You have to register an AdminModel first in admin.py :

from django.contrib import admin
from yourapp.models import YourModel

class YourAdmin(admin.ModelAdmin):
    pass

admin.site.register(YourModel, YourAdmin)

Now you can add different behavior to it. For example you can add the list of fields shown in the edit/add page:

class YourAdmin(admin.ModelAdmin):
    fields = ['field1', 'field2']

This can be names of the model fields, model properties or model methods. Methods are displayed read-only.

If you want to have one field read-only explicitly add this:

class YourAdmin(admin.ModelAdmin):
    fields = ['field1', 'field2']
    readonly_fields = ['field2']

Then you have the option to overwrite the display of the field completely by adding a method with the same name. You will not even need a model field/method with that name, then:

class YourAdmin(admin.ModelAdmin):
    fields = ['field1', 'field2']
    readonly_fields = ['field2']

    def field2(self, obj):
        return '*** CLASSIFIED *** {}'.format(obj.field2)

With django.utils.safestring.mark_safe you can return HTML code as well.

All other options of the Admin are available, except the widget configuration as it applies to the writable fields only.

I might be a little confused as to what you want but you might want to look into model properties. Here is an example for my current project.

Code inside your model:

class Textbook(models.Model):
    #other fields

    @property
    def NumWishes(self):
        return self.wishlist_set.count()

Then you can just display it on the admin page.

class Textbook_table(admin.ModelAdmin):
    fields = ["""attributes that are saved in the model"""]
    list_display = ("""attributes that are saved in the model""", 'NumWishes'')

So now I can display NumWishes in the admin page but it doesn't need to be created with the model.

Hello in the class admin modify the permission method

@admin.register(my_model)
class My_modelAdmin(admin.ModelAdmin):


    def has_delete_permission(self, request, obj=None):
        return False

    def has_change_permission(self, request, obj=None):
        return False

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM