tolomea / django-data-browser

Django app for user friendly querying of Django models
BSD 3-Clause "New" or "Revised" License
350 stars 28 forks source link

Is there any way to show editable=False fields? #31

Closed liyu1981 closed 3 years ago

liyu1981 commented 3 years ago

View 2021-08-05 23-35-47

As titled and as an example in the screenshot. Usually our model will have created_at and updated_at fields but is editable=False. In django admin UI it is reasonable to not showing it because they are auto created/updated. But as in data browse, this does not make sense as not able to browse it.

So is there any way to show them? Like the dbb annotation?

tolomea commented 3 years ago

tl;dnr Yes, set ddb_extra_fields = ["created_at", "updated_at"] on your admin.

The editable=False is not the problem and not related. By default DDB only shows the fields (and models) the current user can see in the Admin. This means it reflects any access control you might have going on. You can override this in a few ways which are documented here https://github.com/tolomea/django-data-browser#id9

For your case you want set ddb_extra_fields = ["created_at", "updated_at"] on your admin, right next to the standard fields, readonly_fields etc.

There is also a function version that could be used as:

def get_ddb_extra_fields(self, request):
    return super().get_ddb_extra_fields(request) +  ["created_at", "updated_at"]

(The super().get_ddb_extra_fields(request) assumes you are including data_browser.helpers.AdminMixin in the parent classes)

A useful setup (and the one we use at work) is to have a common base admin which uses the function form to add project wide stuff like created_at and updated_at (we also have these, in our case in a common base model). And then in the individual admins add any admin specific ones with ddb_extra_fields=

liyu1981 commented 3 years ago

thanks. I tried in admin.py and it works! But because this created_at/updated_at are so common in all of our models, as well as there are other editable=False fields, defining them one by one can be very tedious.

So I end up in using following piece of code to automatically enable all editable=False fields of my models in admin.py

from django.apps import apps
from django.contrib import admin
from django.contrib.admin.sites import AlreadyRegistered
from django.db.models.query_utils import DeferredAttribute

def find_model_ineditable_fields(model):
    ret = []
    for attr_name in dir(model):
        a = getattr(model, attr_name)
        if isinstance(a, DeferredAttribute) and hasattr(a, 'field') and a.field.editable == False:
            ret.append(attr_name)
    return ret

app_models = apps.get_app_config('keeper_api').get_models()
for model in app_models:
  try:
    model_admin = type('%sAdmin' % model.__name__, (admin.ModelAdmin,), {
      'ddb_extra_fields': find_model_ineditable_fields(model)
    })
    admin.site.register(model, model_admin)
  except AlreadyRegistered:
    pass

May be further way is to only enable this part of code in dev copy.

I was thinking that if DDB can automatically enable viewing all editable=False fields in development mode then will be good. But since above code also works, hopes this can help others with the same trouble.