Last active
July 30, 2019 20:50
-
-
Save Sovetnikov/ebd27eb1d783f9d66a205ac139f9f14b to your computer and use it in GitHub Desktop.
django-fsm-log admin model inline for Django 1.7.7
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib.admin import TabularInline | |
from django.contrib.admin.utils import flatten_fieldsets | |
from django.contrib.contenttypes.models import ContentType | |
from django.db import models | |
from django.forms import BaseInlineFormSet, BaseModelFormSet | |
from django_fsm_log.models import StateLog | |
# Making possible to show django inline model admin without actual foreign key to parent model | |
# Works by making new model that has required FK (just to pass startup checks) and overriding actual queryset generated in FormSet | |
# For Django 1.7.7 | |
# Use as: | |
# class ParentModelStateLogInlineAdmin(FSMStateInlineClass(ParentModel)): | |
# pass | |
# class ParentModelAdmin(ModelAdmin): | |
# model = ParentModel | |
# inlines = (ParentModelStateLogInlineAdmin,) | |
__all__ = ('FSMStateInlineClass',) | |
class FSMStateInlineFormset(BaseInlineFormSet): | |
def __init__(self, data=None, files=None, instance=None, | |
save_as_new=False, prefix=None, queryset=None, **kwargs): | |
if instance is None: | |
self.instance = self.fk.rel.to() | |
else: | |
self.instance = instance | |
self.save_as_new = save_as_new | |
# Just creating queryset for StateLog, ignoring given in args | |
qs = self.get_queryset() | |
# Skipping BaseInlineFormSet.__init__ right into BaseModelFormSet.__init__ | |
BaseModelFormSet.__init__(self, data, files, prefix=prefix, | |
queryset=qs, **kwargs) | |
def get_queryset(self): | |
ct = ContentType.objects.get_for_model(self.instance) | |
if self.instance.pk is not None: | |
# Resulting queryset | |
# Ordering is here, one can make code to respect ordering from InlineClass | |
qs = StateLog.objects.filter(content_type=ct, object_id=self.instance.pk).order_by('-timestamp') | |
else: | |
qs = StateLog.objects.none() | |
return qs | |
def FSMStateInlineClass(to): | |
name = '{0}StateLog'.format(to.__name__) | |
class Meta: | |
app_label = '' | |
managed = True | |
pass | |
attrs = {'__module__': __name__, 'Meta': Meta} | |
fields = { | |
# FK that django admin inlines check requires | |
'orig_object_link': models.ForeignKey(to=to, related_name=None), | |
# Parent link is required to inherited model | |
'state_log': models.OneToOneField(to=StateLog, parent_link=True, related_name=None) | |
} | |
attrs.update(fields) | |
new_model = type(name, (StateLog,), attrs) | |
# Fix for django-reversion | |
setattr(to, '{0}_set'.format(name.lower()), StateLog.objects.none()) | |
class StateInline(TabularInline): | |
model = new_model | |
can_delete = False | |
def has_add_permission(self, request): | |
return False | |
def has_delete_permission(self, request, obj=None): | |
return False | |
def has_change_permission(self, request, obj=None): | |
return False | |
formset = FSMStateInlineFormset | |
fields = ('timestamp', 'by', 'state_display') | |
readonly_fields = ('state_display',) | |
def state_display(self, log): | |
try: | |
return log.get_state_display() | |
except Exception as e: | |
return str(e) | |
state_display.short_description = 'State' | |
# All fields is readonly | |
def get_readonly_fields(self, request, obj=None): | |
if self.declared_fieldsets: | |
readonly = flatten_fieldsets(self.declared_fieldsets) | |
else: | |
readonly = list(set( | |
[field.name for field in self.opts.local_fields] | |
)) | |
readonly += list(self.readonly_fields) | |
return readonly | |
return StateInline |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment