4

I need to keep information about filtering and searching in Django admin change page.

So when user filters by "?away_team__id__exact=267821", I need to append this query to change page url.

Let's say we filtered objects by query above. This is the url of change list:

http://127.0.0.1:8000/matches/match/?away_team__id__exact=267821

I want to make change field which redirects user to change page of the current object and appends query to the url so instead:

http://127.0.0.1:8000/matches/match/2009/change/

The url will be:

http://127.0.0.1:8000/matches/match/2009/change/?away_team__id__exact=267821

The problem is that I couldn't access request in the custom field method. I tried to do it using template language but without success, I get:

http://127.0.0.1:8000/matches/match/1996/change/?{{%20request.GET.urlencode%20}}

This is the method:

def change(self,obj):
    return mark_safe(f"""<a class="changelink" href="{reverse("admin:matches_match_change",args=(obj.pk,))}"""+"?{{ request.GET.urlencode }}\""+"><span class='icon'>Zmeniť</span></a>")

Do you know how to do that?

EDIT

This is because I need to create a NEXT and PREVIOUS buttons in change object page so user can step directly to the next object.

3
  • You can extract the querystring from the change list in the change view itself from request.META['HTTP_REFERER'] in order to process that information. Commented Aug 23, 2018 at 14:44
  • @schwobaseggl Overriding change view is a good idea, I didn't know that there is change_view function in admin. Thanks Commented Aug 23, 2018 at 14:48
  • @schwobaseggl Hm, but when user clicks first time on NEXT button, the HTTP_REFERER will be worthless... Commented Aug 23, 2018 at 14:52

3 Answers 3

11

You can just store the current request on the admin instance in the change list view to make it available to subsequent methods:

class YourAdmin(ModelAdmin):
    def changelist_view(self, request, *args, **kwargs):
        self.request = request
        return super().changelist_view(request, *args, **kwargs)

    def change(self, obj):
        request = getattr(self, 'request', None)
        if request:
           # use request.GET to construct the link
Sign up to request clarification or add additional context in comments.

2 Comments

This was helpful when I wanted a custom field that includes a link to the change_form for the instance (including preserving the list filter parameters) but doesn't make the whole field into a link (i.e. including it in list_display_links isn't ideal). I used the above and then used self.get_preserved_filters(request) to get the querystring for the change form URL. e.g. link = "<a href='{}?{}'>Link</a>".format(obj.get_change_url(), self.get_preserved_filters(request)). Then the custom field function returns link + "Whatever you want not in the link".
Watch out for a race condition with this approach. ModelAdmin instance is created once (per a web worker process) and potentially shared by multiple (concurrent) requests. Thus in your custom field method you may be reading a value just set by another concurrent request.
0

I put together a mixin for extending AdminModels for accessing to the request parameters:

class RequestParameters_AdminMixin(object):
    """adds the request GET parameters in AdminModel variable request_parameters""" 
    request_parameters={}

    def changelist_view(self, request, *args, **kwargs):
        self.request_parameters = request.GET
        return super().changelist_view(request, *args, **kwargs)

Use: class TaskModelAdmin(RequestParameters_AdminMixin, original_TaskModelAdmin): def column_name(self, obj): if 'is_maintask' in self.request_parameters: ...

1 Comment

This is subject to a race condition as well. ModelAdmin instances are shared among requests during the lifetime of a web worker process.
0

You can use request in the custom fields of list_display by overriding get_list_display() as shown below. *The example below gets the current user's first and last names in test1 and test2 respectively and you can see the original code of get_list_display() in GitHub:

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ('test1', 'test2')

    def (self, request):
        self.request = request # Set `request`
        return self.list_display

    def test1(self, obj):
        return self.request.user.first_name

    def test2(self, obj):
        return self.request.user.last_name

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.