Understanding django admin readonly_fields

2024/10/7 14:28:38

I created some code to differentiate between two usergroups in Django admin, resulting in showing all fields readonly or only some of them, which are set directly in the ModelAdmin class.

At first here is the code:

class PersonAdmin(admin.ModelAdmin):readonly_fields = ('created_at','created_by',)def get_form(self, request, obj=None, **kwargs):if obj:     # we are in edit modeif request.user.is_superuser:self.readonly_fields = ()else:for group in request.user.groups.all():if str(group) == 'readonlyuser':allfields = tuple(obj._meta.get_all_field_names())self.readonly_fields = allfieldsreturn super(PersonAdmin, self).get_form(request, obj, **kwargs)

I divide between the groups and set the fields accordingly. Everything works fine if users from the two groups are not logged in at the same time! After a 'readonly' user logged in, the adminuser will get all fields readonly too.

My inspections provided a solution also: If I put an additional if statement for the adminuser within the for block everything works as expected.

if str(group) == 'adminuser':self.readonly_fields = PersonAdmin.readonly_fields

Why is that and what's happening there?

I have no special cache settings made and it happens on the dev server as well as on an Apache with WSGI.

From my understanding request.user.groups.all() should return all groups the currently logged in user belongs to. Where does Django get the allfields (readonly) from, if another user on a different IP and session match this if block?

Answer

The ModelAdmin is only instantiated once for all requests that it receives. So when you define the readonly fields like that, you're setting it across the board permanently.

As long as you're running Django 1.2+, there's a get_readonly_fields method you can use instead for exactly this purpose:

class MyModelAdmin(admin.ModelAdmin):...def get_readonly_fields(self, request, obj=None):if request.user.is_superuser:return super(MyModelAdmin, self).get_readonly_fields(request, obj)else:return ('created_at', 'created_by')

Remove the readonly_fields attribute from your ModelAdmin or set it to the fields that should be readonly for everyone. Then, in the else block specify all the fields that should be readonly only for non-superusers.

https://en.xdnf.cn/q/70230.html

Related Q&A

The seaborn styles shipped by Matplotlib are deprecated since 3.6

The seaborn styles shipped by Matplotlib are deprecated since 3.6, as they no longer correspond to the styles shipped by seaborn. However, they will remain available as seaborn-v0_8-<style>. Alte…

Python: Can the pydoc module output HTML docs with relative paths?

I am using the pydoc module to output documentation for some types which I have defined with the C API. The types I want to document dont exist until the interpreter has been embedded inside my C progr…

How to generate coverage report for http based integration tests?

I am writing integration tests for a project in which I am making HTTP calls and testing whether they were successful or not.Since I am not importing any module and not calling functions directly cover…

Does Webdriver support pagefactory for Python?

I was reading about page objects and design patterns on the Webdriver project site and came across pagefactory. It doesnt look like the Webdriver for Python API includes pagefactory. Is this true?

Truncated versus floored division in Python

To establish context, Im talking about integer arithmetic only, on large integers so going via floating point isnt an option, and using negative numbers so the difference between floored and truncated …

when restoring from a checkpoint, how can I change the data type of the parameters?

I have a pre-trained Tensorflow checkpoint, where the parameters are all of float32 data type.How can I load checkpoint parameters as float16? Or is there a way to modify data types of a checkpoint?F…

Opencv Python open dng format

I cant figure out how to open a dng file in opencv. The file was created when using the pro options of the Samsung Galaxy S7. The images that are created when using those options are a dng file as well…

VSCode: Set environment variables via script

I have a shell script env.sh containing statements like export ENV_VAR1 = 1. On Linux terminal, I can use . env.sh or source env.sh to set the environment variables. How to set the environment variable…

TensorFlow performance bottleneck on IteratorGetNext

While fiddling around with TensorFlow, I noticed that a relatively simple task (batching some of our 3D accelerometer data and taking the sum of each epoch) was having relatively poor performance. Here…

SQLAlchemy - How to access column names from ResultProxy and write to CSV headers

I am trying to use SQLAlchemy to establish a connection to a PostgreSQL Database, execute a SQL query and print the output of the file to a file in linux. from sqlalchemy import create_engine import ya…