Repository URL to install this package:
|
Version:
0.0.1 ▾
|
dj-kaos-utils
/
admin.py
|
|---|
import threading
from django.contrib import admin
from django.contrib.admin.options import BaseModelAdmin, InlineModelAdmin
from django.db.models import Count
from django.utils.safestring import mark_safe
class EditReadonlyAdminMixin(BaseModelAdmin):
edit_readonly_fields = ()
def get_edit_readonly_fields(self, request, obj=None):
return self.edit_readonly_fields
def get_readonly_fields(self, request, obj=None):
readonly_fields = super().get_readonly_fields(request, obj)
if obj: # editing an existing object
return self.get_edit_readonly_fields(request, obj) + readonly_fields
return readonly_fields
class SluggableAdminMixin(EditReadonlyAdminMixin):
slug_source = None
def get_edit_readonly_fields(self, request, obj=None):
return super().get_edit_readonly_fields(request, obj) + ('slug',)
def get_prepopulated_fields(self, request, obj=None):
assert self.slug_source
prepopulated_fields = super().get_prepopulated_fields(request, obj)
if obj: # editing an existing object
return prepopulated_fields
return {**prepopulated_fields, 'slug': (self.slug_source,)}
def render_anchor_tag(href, text=None, blank=True):
target_blank = '''target="_blank"''' if blank else ''
return mark_safe(f"""
<a {target_blank} href={href}>
{text or href}
<a/>
""")
def anchor_tag(obj, link_field):
if obj.pk:
return render_anchor_tag(getattr(obj, link_field))
return ""
class LinkableAdminMixin(BaseModelAdmin):
link_fields = ()
def get_readonly_fields(self, request, obj=None):
readonly_fields = super().get_readonly_fields(request, obj)
if obj:
for link_field in self.link_fields:
f = lambda x: anchor_tag(x, link_field)
f.__name__ = link_field
setattr(self, link_field, f)
return (*readonly_fields, *self.link_fields)
return readonly_fields
# From https://gist.github.com/rafen/eff7adae38903eee76600cff40b8b659
class NoQSActionsAdminMixin(BaseModelAdmin):
"""
Admin mixin enables actions that can be executed with no items selected on the admin change list.
"""
extended_actions = []
def changelist_view(self, request, extra_context=None):
# if a extended action is called and there's no checkbox selected, select one with
# invalid id, to get an empty queryset
if 'action' in request.POST and request.POST['action'] in self.extended_actions:
if not request.POST.getlist(admin.ACTION_CHECKBOX_NAME):
post = request.POST.copy()
post.update({admin.ACTION_CHECKBOX_NAME: 0})
request._set_post(post)
return super().changelist_view(request, extra_context)
def admin_action_message(count, errors_count, success_msg, error_msg):
success_count = count - errors_count
message = ""
if success_count:
message += success_msg.format(success_count)
if errors_count:
if message:
message += " "
message += error_msg.format(errors_count)
return message
class AddInlineMixin(InlineModelAdmin):
def get_queryset(self, request):
queryset = super().get_queryset(request)
return queryset.none() # no existing records will appear
class ListInlineMixin(InlineModelAdmin):
def has_add_permission(self, request, obj):
return False
class ReadOnlyInlineMixin(ListInlineMixin):
def has_change_permission(self, request, obj=None):
return False
class AutoUserAdmin(admin.ModelAdmin):
user_field = None
def formfield_for_foreignkey(self, db_field, request, **kwargs):
field = super().formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == self.user_field and field.initial is None:
field.initial = request.user
return field
class ModelAdminRequestMixin(object):
"""
from https://stackoverflow.com/a/50380461/1437754
"""
def __init__(self, *args, **kwargs):
# let's define this so there's no chance of AttributeErrors
self._request_local = threading.local()
self._request_local.request = None
super(ModelAdminRequestMixin, self).__init__(*args, **kwargs)
def get_request(self):
return self._request_local.request
def set_request(self, request):
self._request_local.request = request
def changeform_view(self, request, *args, **kwargs):
# stash the request
self.set_request(request)
# call the parent view method with all the original args
return super(ModelAdminRequestMixin, self).changeform_view(request, *args, **kwargs)
def add_view(self, request, *args, **kwargs):
self.set_request(request)
return super(ModelAdminRequestMixin, self).add_view(request, *args, **kwargs)
def change_view(self, request, *args, **kwargs):
self.set_request(request)
return super(ModelAdminRequestMixin, self).change_view(request, *args, **kwargs)
def changelist_view(self, request, *args, **kwargs):
self.set_request(request)
return super(ModelAdminRequestMixin, self).changelist_view(request, *args, **kwargs)
def delete_view(self, request, *args, **kwargs):
self.set_request(request)
return super(ModelAdminRequestMixin, self).delete_view(request, *args, **kwargs)
def history_view(self, request, *args, **kwargs):
self.set_request(request)
return super(ModelAdminRequestMixin, self).history_view(request, *args, **kwargs)
class TrackObjAdminMixin:
def get_form(self, request, obj=None, **kwargs):
request._obj_ = obj
return super().get_form(request, obj, **kwargs)
class RequestFormInlineMixin:
def get_formset(self, request, obj=None, **kwargs):
formset = super(RequestFormInlineMixin, self).get_formset(request, obj=obj, **kwargs)
formset.form.request = request
return formset
class RelatedCountAdmin:
count_fields = ()
def get_count_fields(self, request, obj=None):
return self.count_fields
def get_queryset(self, request):
qs = super(RelatedCountAdmin, self).get_queryset(request)
qs = qs.annotate(*(Count(field) for field in self.get_count_fields(request)))
return qs
class NameSlugModelAdmin(
admin.ModelAdmin
):
search_fields = ('name',)