Администратор Django: Как получить доступ к объекту запроса в admin.py для методов list_display? - PullRequest
22 голосов
/ 08 апреля 2009

Я добавил метод 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'?

Ответы [ 9 ]

16 голосов
/ 08 апреля 2009
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)
15 голосов
/ 10 мая 2014

Я решаю свою проблему таким образом.

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
3 голосов
/ 08 апреля 2009

Нет прямого способа сделать это. Я вижу 2 возможных решения.

  • Использовать хранилище локальных потоков для одного и того же объекта запроса

    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')
    
2 голосов
/ 17 мая 2018

Описано, как преобразовать это в миксин с добавлением бита безопасности потока, основанного на ответе @ 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)

Подкласс ModelAdmin с миксином:

class PollAdmin(ModelAdminRequestMixin, admin.ModelAdmin):
    pass

... и вы можете просто вызвать self.get_request() из любого метода.

2 голосов
/ 26 марта 2018

Маленький код для уточнения Диего Пуэнте ответ (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.request в get_queryset (не объявляя его в __init__), PyCharm выдаст предупреждение Instance attribute attribute_name defined outside __init__.

0 голосов
/ 18 апреля 2018

Это отредактированная версия ответа @ 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})
0 голосов
/ 13 мая 2016
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()
        # ... 
0 голосов
/ 04 мая 2009

Что не так с этим:

def highlight_link(self, request):
    # access start_date here
0 голосов
/ 17 апреля 2009

Я попробовал другие ответы, оставленные здесь, и столкнулся с проблемами, которые для меня становились сложными. Я играл с 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
...