Reputation: 927
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
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