Django admin 經常使用定製

歷史緣由,使用django1.6.5,shame on me....html

 

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中日期範圍過濾python

相關文章
相關標籤/搜索