1

So, I have this code

class PostAdmin(models.ModelAdmin):
    # ...
    def display_confirm_button(self, obj):
        # some code
    # ...

How to get current user in display_confirm_button method?

react
  • 159
  • 2
  • 9
  • check this answer http://stackoverflow.com/a/10993961/4117381 and this https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model – Ahmed Hosny Feb 11 '16 at 10:19
  • @AhmedHosny those links seem to be irrelevant; they are talking about using the request in saving the model, which is not at all what OP was asking. – Daniel Roseman Feb 11 '16 at 10:21
  • @AhmedHosny i need to get user without saving – react Feb 11 '16 at 10:24
  • You only have access to the `display_confirm_button` object in that method. You can't access the request, so you can't access the user. If you explain where you are trying to use the `display_confirm_button` method, there might be another way to solve your problem. – Alasdair Feb 11 '16 at 10:29
  • @Aleksey Sergeev And you can use request in other methods, check the second link – Ahmed Hosny Feb 11 '16 at 10:29
  • @Alasdair perhaps, this is not better solution(in deleted answer), but I wrote a simple test to check the correctness this, in `__init__` I wrote - `self.some = 0` and in `get_queryset` - `self.some += 1`, and in different requests it always 1. – react Feb 11 '16 at 11:00
  • I tested using `runserver`, and got a different result - `self.some` increases with each request for me. As I said in my previous comment, there might be a way to avoid using hacks like setting `self.request` or using thread locals. However, you haven't said what you're trying to do with your `display_confirm_button` method, so I can't tell. – Alasdair Feb 11 '16 at 11:38
  • @Alasdair so, in `display_confirm_button(self, obj)` I render(in template) a html button, which should be visible only for some users, for this I need user from request(for template context). – react Feb 11 '16 at 11:56
  • How do you access `display_confirm_button` in your template? – Alasdair Feb 11 '16 at 12:02
  • @Alasdair `load=loader.get_template('template.html')` and `display_confirm_button` return `load.render(context)`. – react Feb 11 '16 at 12:04
  • That's the code *in* `display_confirm_button`. What is the code that *calls* `display_confirm_button`? For example, do you include it in `list_display`? – Alasdair Feb 11 '16 at 12:10
  • @Alasdair of course it in `list_display` – react Feb 11 '16 at 12:14
  • It's not obvious, otherwise I wouldn't have asked ;) – Alasdair Feb 11 '16 at 12:26
  • Anyway, I think you can get the result you want by overriding `get_list_display`. See my answer below. – Alasdair Feb 11 '16 at 12:27

2 Answers2

7
class PostAdmin(models.ModelAdmin):
    # ...
    def display_confirm_button(self, obj):
        # some code
    # ...

To access the logged in user, you need access to the request object. It isn't possible to access the request in your display_confirm_button method, since you only have access to obj, the object that is being edited.

The solution is to override get_list_display, which has access to the request object. You can then define your display_confirm_button inside get_list_display where it has access to the request, and include the display_confirm_button callable in the list that you return.

class MyModelAdmin(admin.ModelAdmin):
    def get_list_display(self, request):

        def display_confirm_button(obj):
            out = logic_that_requires_user(request.user)
            return out

        return ['field1', 'field2', display_confirm_button, ...]
Georgi Yanchev
  • 1,215
  • 10
  • 10
Alasdair
  • 298,606
  • 55
  • 578
  • 516
2

The best solution IMHO is to store the current user in changelist_view to have it accessible in your method.

class PostAdmin(models.ModelAdmin):
    def changelist_view(self, request, extra_context=None):
        setattr(self, 'user', request.user)
        return super().changelist_view(request, extra_context)

    def display_confirm_button(self, obj):
        # you can use self.user here

You can keep this DRY by creating a mixin like this:

class CurrentUserMixin(object):
    def changelist_view(self, request, extra_context=None):
        setattr(self, 'user', request.user)
        return super().changelist_view(request, extra_context)


class PostAdmin(CurrentUserMixin, models.ModelAdmin):
    def display_confirm_button(self, obj):
        # you have self.user here