krayzk
krayzk

Reputation: 927

Using reverse url lookup in django template with keyword arguements

I would like to use the reverse url lookup available in a django template using keyword arguments instead of positional ones.

I have it working using positional arguments just fine as such:

HTML:

    <a href="{% url 'download' customer.pk %}">download</a>

URL:

    (r'^generator/download/(?P<customer_id>\d+)/$', 'generator.views.send_file', name='download'),

View definition:

    def send_file(request, customer_id):

The problem is that I am noticing a security flaw in that now anyone can simply enter as a url like:

    /generate/download/<any number>/

and download a file that is meant only for someone else. I understand that this risk might be able to be mitigated by using user permissions etc, but I still would like to add another layer of security just in case. Maybe I am wrong in my thinking that a keyword argument is safer in this regard because it is not simply available to be passed in the url... But that is what I am thinking.

The code as I think it should work looks like:

HTML:

    <a href="{% url 'download' customer_id=customer.pk %}">download</a>

URL:

    (r'^generator/download/$', 'generator.views.send_file', name='download'),

View definition:

    def send_file(request, customer_id=None):
        customer = get_object_or_404(Customer, pk=customer_id)
        ... other code

meaning if /generate/download/ is entered in the url (without the accompanying kwarg) it would just give them 404.

but I am getting the following error when I try to use this code:

Reverse for 'download' with arguments '()' and keyword arguments '{u'customer_id': 33}' not found. 1 pattern(s) tried: ['generator/download/$']

I'm sure it is something silly that I simply passed over in the django url dispatcher docs, or perhaps it is in the way I am defining my view (perhaps I need **kwargs as the argument?) but I can't seem to find it for the life of me.

Your help is much appreciated.

Upvotes: 0

Views: 2318

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599788

Your assumption is unfortunately completely wrong. Keyword arguments are passed in the URL, they are simply sent to the view function in a different way - in kwargs instead of args.

The simplest way to solve your problem is just to check the user in the download function itself.

def download(request, pk):
    obj = Download.objects.get(pk)
    if obj.customer_id != request.user.id:
        return HttpResponseForbidden()

Upvotes: 1

Related Questions