I have a BaseModel that I’m using across all my applications. BaseModel provides common auditing fields:
“created”, “created_by”, “modified”, “modified_by”
created and modified are DateTimeField using django’s built-in auto_now_add and auto_now functionality.
created_by and modified_by are CharFields as the values can be a username, system action identifier, or API action authenticated outside of the auth framework (for example a webhook).
Within the admin I’m setting these fields to readonly_fields:
readonly_fields = ("created", "created_by", "modified", "modified_by")
And I’m overriding the admin save_model to capture the admin user to set the create_by or modified_by as documented in this example
https://docs.djangoproject.com/en/3.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
In the spirit of DRY I’m researching how to create a Mixin that will provide the base readonly_fields and save_model to each app’s ModelAdmin. This is what I have come up with for the BaseAdminMixin:
class BaseAdminMixin:
base_readonly_fields = ("created", "created_by", "modified", "modified_by")
def get_readonly_fields(self, request, obj=None):
if self.readonly_fields:
return self.readonly_fields + self.base_readonly_fields
else:
return self.base_readonly_fields
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.created_by = request.user.get_username()
if change:
obj.modified_by = request.user.get_username()
super().save_model(request, obj, form, change)
This approach is passing all the tests I wrote when I was repeating the readonly_fields and save_model code in every ModelAdmin class.
This is a new area of using django for me so I’m looking for feedback on this approach.