Django Admin:如何访问 admin.py 中的 request 对象,用于 list_display 方法?

发布于 2024-07-17 12:54:32 字数 484 浏览 6 评论 0原文

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

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 中的请求对象?

I've added a method highlight_link to my model's admin.py class:

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

It returns a custom link for (I've left out highlight_link.short_description for brevity) each record returned in the change list. Which is great. But I'd like to inspect the current query string and change the custom link based on that. Is there a way to access the request object within highlight_link?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

沉鱼一梦 2024-07-24 12:54:32

我用这种方式解决了我的问题(对于 1.7 以下的 django):

class MyClassAdmin(admin.ModelAdmin):

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

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

UPDATE

在 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

I solve my issue this way (for django under 1.7):

class MyClassAdmin(admin.ModelAdmin):

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

Now i can use self.request in any place

UPDATE

Changed in Django 1.6:
The get_queryset method was previously named queryset.

class MyClassAdmin(admin.ModelAdmin):

    def get_queryset(self, request):
        qs = super(MyClassAdmin, self).get_queryset(request)
        self.request = request
        return qs
魄砕の薆 2024-07-24 12:54:32
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)
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)
不再让梦枯萎 2024-07-24 12:54:32

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

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)

Subclass ModelAdmin with the mixin:

class PollAdmin(ModelAdminRequestMixin, admin.ModelAdmin):
    pass

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

Described how to refactor this into a mixin, with addition of the thread-safety bit based on @taha-jahangir's answer. Here's the mixin:

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)

Subclass ModelAdmin with the mixin:

class PollAdmin(ModelAdminRequestMixin, admin.ModelAdmin):
    pass

... and you can just call self.get_request() from any method.

三人与歌 2024-07-24 12:54:32

小代码澄清了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)

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

如果在 get_queryset 方法中定义 self.request(未在 __init__ 中声明),PyCharm 将生成警告 Instance attribute attribute_name在 __init__ 之外定义< /代码>。

Small code clarify for Diego Puente answer (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)

So you can get self.request from any other method of MyClassAdmin.

If define self.request in get_queryset method (without declaring it in __init__) PyCharm will generate warning Instance attribute attribute_name defined outside __init__.

我纯我任性 2024-07-24 12:54:32

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

  • 使用线程局部变量存储到同一请求对象

    从 django.utils._threading_local 导入局部变量 
    
      全局变量=局部变量() 
    
      RadioGridAdmin 类(admin.ModelAdmin): 
        def __call__(自身,请求,*args,**kwargs): 
            全局['radio_grid_admin_request'] = 请求 
            返回 super(RadioGridAdmin, self).__call__(request, *args, **kwargs) 
    
        def 高亮链接(自身): 
            请求=全局['radio_grid_admin_request'] 
            # request.GET处理 
            return ('一些自定义链接') 
      
  • 如果您使用简单的非线程 Django 安装,则可以将请求对象保存为属性:

    类 RadioGridAdmin(admin.ModelAdmin): 
        def __call__(自身,请求,*args,**kwargs): 
            自我请求=请求 
            返回 super(RadioGridAdmin, self).__call__(request, *args, **kwargs) 
    
        def 高亮链接(自身): 
            # self.request.GET处理 
            return ('一些自定义链接') 
      

The is no direct way to accomplish this. I see 2 possible solutions.

  • Use a thread locals store to same request object

    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')
    
  • If you are using simple non-threaded Django installation it is possible to save request object just as attribute:

    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')
    
堇年纸鸢 2024-07-24 12:54:32

这是 @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})

This is edited version of @user27478 answer, which uses thread-local vars:

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})
野心澎湃 2024-07-24 12:54:32

我尝试了这里留下的其他答案,但遇到了对我来说变得越来越复杂的问题。 我尝试了一下 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

I tried the other answers left here and ran into issues that for me, were getting complex. I played around with def __call__() and came up with the following. This probably isn't the correct way to do this, but it works...

grab the GET variable here (all within class RadioGridAdmin as described above in my initial post):

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

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

and since it's global, you can now access it here:

def highlight_link(self):
    # access start_date here
负佳期 2024-07-24 12:54:32
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()
        # ... 
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()
        # ... 
剪不断理还乱 2024-07-24 12:54:32

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< /a>

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.

Source: https://gist.github.com/pricco/24826bae3d5102d963eb13ecc0493f33

帅哥哥的热头脑 2024-07-24 12:54:32

这是什么问题:

def highlight_link(self, request):
    # access start_date here

What's wrong with this:

def highlight_link(self, request):
    # access start_date here
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文