Django admin 常用定制

原创
2018/01/09 17:30
阅读数 2.4K

历史原因,使用django1.6.5,shame on me....

 

1. 显示admin日志

# 某个app下,建立admin.py 内容如下

from django.contrib.admin.models import LogEntry

class LogEntry_Admin(admin.ModelAdmin):
    list_display = ['id', 'user', 'action_time', 'content_type', 'object_id', 'object_repr', 'change_message']

admin.site.register(LogEntry, LogEntry_Admin)
# 有自动注册的库,未使用 https://github.com/Mimino666/django-admin-autoregister


# 之后记录日志如下:
        try:
            LogEntry.objects.log_action(
                user_id=request.user.pk,
                content_type_id=ContentType.objects.get_for_model(FooModel).pk,
                object_id=None,
                object_repr='foo verbose_name',
                action_flag=0,
                change_message='change foo',
        except Exception as e:
            logging.error(traceback.format_exc())

 

2. ModelAdmin 的几个字段的功能

# 列表中需要展示的字段
# 枚举
list_display = ['id', 'name']
# 排除
list_display = [field.name for field in MyModel._meta.fields if field.name != 'foo']


# 列表过滤器
list_filter = ['created', 'updated', 'status']

# 可搜索的字段
search_fields = ['name']

# 动作字段
actions = ['foo', 'bar']
    
# 只读显示字段, 一般用于添加链接
readonly_fields = ['link']

# 排序字段
ordering = ['-created']

# 查询时同时取出外建对应的model
list_select_related = True

# 列表每页显示多少条
list_per_page = 50

 

3.添加链接字段

from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse


class Foo_Admin(admin.ModelAdmin):
    list_display = ['id', 'bar_link'] # 列表页中的链接字段
    readonly_fields = ['foo_links'] # 编辑页中的链接字段

    def bar_link(self, obj):
        try:
            # model修改页链接, admin:app名称_模型名称_change
            link = reverse("admin:barapp_barmodel_change", args=(bar.id,))
            return mark_safe('<a href="{}" target="_blank">{}</a>'.format(link, bar.id))
        except BarModel.DoesNotExist:
            return u'bar不存在'
    # 方法名后的short_description是其作为字段的描述
    bar_link.short_description = u'bar链接'

    def foo_links(self, obj):
        try:
            links = ''
            foos = FooModel.objects.filter(name=obj.name)
            for foo in foos:
                link = reverse("admin:fooapp_foomodel_change", args=(foo.id,))
                linkhtml = mark_safe('<a href="{}" target="_blank">{}</a>'.format(link, foo.id))
                links = links + ' ' + linkhtml
            return links
        except:
            return None
    foo_links.short_description = u'foo链接'
    # 允许html标签
    foo_links.allow_tags = True

 

4.自定义动作

class Foo_Admin(admin.ModelAdmin):
    actions = ['my_action']

    def my_action(self, request, queryset):
        for item in queryset:
            PROC(item)
        # 把消息显示给用户
        self.message_user(request, 'success'
    my_action.short_description = 'my wonderful action'

 

5.扩展动作表单, 添加动作参数

class ExtendedActionsMixin(object):
    """
    原始代码及文档地址:https://gist.github.com/rafen/eff7adae38903eee76600cff40b8b659
    """
    # actions that can be executed with no items selected on the admin change list.
    # The filtered queryset displayed to the user will be used instead
    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(ExtendedActionsMixin, self).changelist_view(request, extra_context)

    def get_changelist_instance(self, request):
        """
        Returns a simple ChangeList view instance of the current ModelView.
        (It's a simple instance since we don't populate the actions and list filter
        as expected since those are not used by this class)
        """
        list_display = self.get_list_display(request)
        list_display_links = self.get_list_display_links(request, list_display)
        list_filter = self.get_list_filter(request)
        search_fields = self.get_search_fields(request)
        list_select_related = self.get_list_select_related(request)

        ChangeList = self.get_changelist(request)

        return ChangeList(
            request, self.model, list_display,
            list_display_links, list_filter, self.date_hierarchy,
            search_fields, list_select_related, self.list_per_page,
            self.list_max_show_all, self.list_editable, self,
        )

    def get_filtered_queryset(self, request):
        """
        Returns a queryset filtered by the URLs parameters
        """
        cl = self.get_changelist_instance(request)
        return cl.get_queryset(request)

class Custom_ActionForm(ActionForm):
    """自定义admin动作参数表单
    参考文档: https://github.com/cundi/blog/issues/32
    """
    ARGS_A = 1
    ARGS_B = 2
    ARGS_C = 3

    CHOICES = (
        (ARGS_A, u'AAA'),
        (ARGS_B, u'BBB'),
        (ARGS_C, u'CCC'),
    )
    # 此处用到的下拉选择字段,可按需使用charfiled
    args = forms.ChoiceField(choices=CHOICES, label=u'命令参数')


class Foo_Admin(ExtendedActionsMixin, admin.ModelAdmin):
    actions = ['my_action']
    action_form = Custom_ActionForm
    extended_actions = ['my_action']

    def my_action(self, request, queryset):
        # args为Custom_ActionForm表单中选择的项
        args = int(request.POST.get('args', 0))
        if args == Custom_ActionForm.ARGS_A:
            PROC(args)

 

 

6. 自定义过滤器

from django.contrib import admin
import datetime
from django.contrib.admin import DateFieldListFilter
from django.utils import timezone


class CustomFilter(admin.SimpleListFilter):
    """自定义过滤器"""
    parameter_name = 'foo_status'  # 作为GET请求url参数
    title = u'过滤器名称'
    NEW, SUCCESS, FAIL = '0', '1', '2'

    def lookups(self, request, model_admin):
        return (
            (self.NEW, "新建"),
            (self.SUCCESS, "成功"),
            (self.FAIL, "失败"),
        )

    def queryset(self, request, queryset):
        if not self.value():
            return queryset
        if self.value() == self.NEW:
            return queryset.filter(status=NEW)
        if self.value() == self.FAIL:
            return
        if self.value() == self.SUCCESS:
            return 



class CustomDateTimeFilter(DateFieldListFilter):
    """扩展admin日期过滤器,支持更多日期
    参考: https://stackoverflow.com/questions/37735191/how-do-i-extend-django-admins-datefieldlistfilter-class
    """
    def __init__(self, *args, **kwargs):
        super(CustomDateTimeFilter, self).__init__(*args, **kwargs)

        now = timezone.now()
        # When time zone support is enabled, convert "now" to the user's time
        # zone so Django's definition of "Today" matches what the user expects.
        if timezone.is_aware(now):
            now = timezone.localtime(now)
        today = now.date()

        endyear = now.year
        endmonth = now.month
        if endmonth == 1:
            startmonth = 12
            startyear = now.year - 1
        else:
            startmonth = now.month - 1
            startyear = now.year
        start = datetime.datetime(startyear, startmonth, 1, 0, 0, 0, 0)  # 上月1日0点
        end = datetime.datetime(endyear, endmonth, 1, 0, 0, 0, 0)  # 本月1日0点

        self.links += ((
            (u'昨天', {
                self.lookup_kwarg_since: str(today - datetime.timedelta(days=1)),
                self.lookup_kwarg_until: str(today),
            }),
            (u'前天', {
                self.lookup_kwarg_since: str(today - datetime.timedelta(days=2)),
                self.lookup_kwarg_until: str(today - datetime.timedelta(days=1)),
            }),
            (u'上月', {
                self.lookup_kwarg_since: str(start),
                self.lookup_kwarg_until: str(end),
            }),
        ))



class Foo_Admin(admin.ModelAdmin):
    list_filter = ['status', ('created', CustomDateTimeFilter), CustomFilter]
   

django-admin-rangefilter      # 用于admin中日期范围过滤

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部