31

我在highlight_link模型的 admin.py 类中添加了一个方法:

class RadioGridAdmin(admin.ModelAdmin):
    
    list_display = ('start_time', highlight_link)
    
    def highlight_link(self):
        return ('some custom link')
    
    
admin.site.register(RadioGrid, RadioGridAdmin)

highlight_link.short_description它为更改列表中返回的每条记录返回一个自定义链接(为简洁起见,我省略了)。这是伟大的。但我想检查当前的查询字符串并根据它更改自定义链接。有没有办法在里面访问请求对象highlight_link

4

10 回答 10

26

我这样解决我的问题。

class MyClassAdmin(admin.ModelAdmin):

    def queryset(self, request):
        qs = super(MyClassAdmin, self).queryset(request)
        self.request = request
        return qs

现在我可以self.request在任何地方使用

更新

在 Django 1.6 中更改:get_queryset 方法以前被命名为 queryset。

class MyClassAdmin(admin.ModelAdmin):

    def get_queryset(self, request):
        qs = super(MyClassAdmin, self).get_queryset(request)
        self.request = request
        return qs
于 2014-05-09T21:54:20.943 回答
19
class RadioGridAdmin(admin.ModelAdmin):

    def highlight_link(self, obj):
        return (self.param)

   def changelist_view(self, request, extra_context=None):
        self.param = request.GET['param']
        return super(RadioGridAdmin,self).changelist_view(request, extra_context=extra_context)
于 2009-04-08T13:01:29.500 回答
5

描述了如何将其重构为 mixin,并根据@taha-jahangir 的回答添加了线程安全位。这是混合:

import threading

class ModelAdminRequestMixin(object):
    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)

使用 mixin 子类化 ModelAdmin:

class PollAdmin(ModelAdminRequestMixin, admin.ModelAdmin):
    pass

...您可以self.get_request()从任何方法调用。

于 2018-05-16T21:54:33.957 回答
3

没有直接的方法可以做到这一点。我看到了两种可能的解决方案。

  • 使用线程本地存储到相同的请求对象

    from django.utils._threading_local import locals
    
    globals = locals()
    
    class RadioGridAdmin(admin.ModelAdmin):
      def __call__(self, request, *args, **kwargs):
          globals['radio_grid_admin_request'] = request
          return super(RadioGridAdmin, self).__call__(request, *args, **kwargs)
    
      def highlight_link(self):
          request = globals['radio_grid_admin_request']
          # request.GET processing
          return ('some custom link')
    
  • 如果您使用简单的非线程 Django 安装,则可以将请求对象保存为属性:

    class RadioGridAdmin(admin.ModelAdmin):
      def __call__(self, request, *args, **kwargs):
          self.request = request
          return super(RadioGridAdmin, self).__call__(request, *args, **kwargs)
    
      def highlight_link(self):
          # self.request.GET processing
          return ('some custom link')
    
于 2009-04-08T04:48:11.870 回答
3

小代码澄清了Diego Puente的答案(python 3.6):

class MyClassAdmin(admin.ModelAdmin):
    def __init__(self, model, admin_site): 
        self.request = None
        super().__init__(model, admin_site)

    def get_queryset(self, request):
        self.request = request      
        return super().get_queryset(request)

因此,您可以self.request从任何其他方法获得MyClassAdmin.

如果self.requestget_queryset方法中定义(没有在中声明__init__)PyCharm 将生成警告Instance attribute attribute_name defined outside __init__

于 2018-03-26T10:49:34.367 回答
2

这是@user27478 答案的编辑版本,它使用线程本地变量:

class RadioGridAdmin(admin.ModelAdmin):
    def __init__(self, model, admin_site):
        super().__init__(model, admin_site)
        self._request_local = threading.local()

    def changelist_view(self, request, extra_context=None):
        self._request_local.request = request
        return super().changelist_view(request, extra_context)

    @property
    def _request(self):
        return self._request_local.request

    def example_highlight_link(self, obj):
        changelist = self.get_changelist_instance(self._request)
        url = changelist.get_query_string(new_params={'key1': 1})
于 2018-04-18T06:07:20.437 回答
0

我尝试了此处留下的其他答案,但遇到了对我来说变得越来越复杂的问题。我玩弄def __call__()并想出了以下内容。这可能不是正确的方法,但它有效......

在此处获取 GET 变量(所有在 RadioGridAdmin 类中,如我最初的帖子中所述):

def __call__(self, request, url):
     global start_date
     start_date = request.GET['param']

     return super(RadioGridAdmin, self).__call__(request, url)

由于它是全球性的,您现在可以在这里访问它:

def highlight_link(self):
    # access start_date here
于 2009-04-16T21:00:18.130 回答
0
import threading

_thread_local = threading.local()

def get_thread_local_request():
    return getattr(_thread_local, "request", None)

class RadioGridAdmin(admin.ModelAdmin):
    list_display = ('display_field', ...)

    def display_field(self, obj):
        # ...
        request = get_thread_local_request()
        # ... 
于 2016-05-13T12:48:07.177 回答
0

admin_mixins.py

from functools import partial, update_wrapper, lru_cache

# Django admin call 2 times get_list_display.
# We need to return the same function to make the method sortable using 'admin_order_field'
# https://github.com/django/django/blob/2161db0792f2e4d3deef3e09cd72f7a08340cafe/django/contrib/admin/templatetags/admin_list.py#L84
@lru_cache(maxsize=100)
def cache_display_wrap(f, request):
    wf = partial(f, request)
    nf = update_wrapper(wf, f)
    return nf

  
class ModelAdminMixin(admin.ModelAdmin):
  
    def get_list_display(self, request):
        def check_needs_request(display):
            f = getattr(self, display, None) if not callable(display) else display 
            if f and getattr(f, 'needs_request', False):
              return cache_display_wrap(f, request)
            return display
        return [check_needs_request(display) for display in super().get_list_display(request)]

any_app/admin.py

from django.contrib import admin
from core.admin_mixins import ModelAdminMixin


@admin.register(AnyModel)
class AnyModelAdmin(ModelAdminMixin, admin.ModelAdminMixin):

    list_display = ['id', 'especial_display_with_request']

    def especial_display_with_request(self, request, obj):
        # Make something special with the request
        return obj.any_field
    especial_display_with_request.needs_request = True  # Similar to short_description or any other django admin attr.

来源:https ://gist.github.com/pricco/24826bae3d5102d963eb13ecc0493f33

于 2021-05-18T04:46:03.267 回答
-2

这有什么问题:

def highlight_link(self, request):
    # access start_date here
于 2009-05-04T18:12:46.153 回答