Using reverse url lookup in django template with keyword arguements - python

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:
download
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:
download
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.

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()

Related

Why does a function in views.py require a request parameter in this case in Django?

In url.py I have set up a new path within the main urlpatterns list:
path('ko/', views.ko),
I learned that I need to write this function in views.py to get the webpage going:
def ko(request):
return HttpResponse("It's a page")
My question is why doesn't the function work when I leave the parameter blank instead of request?:
def ko():
return HttpResponse("It's a page")
Running the page when I delete the request parameter outputs a TypeError:ko() takes 0 positional arguments but 1 was given.
If I don't have a request input on the function call of views.ko then why is the request parameter necessary when writing the initial function, what is the request parameter doing, and where is this request parameter going into? What are its attributes? I would really appreciate a thorough response on its qualities.
A view function, or view for short, is a Python function that takes a Web request and returns a Web response. So every view must accept an request parameter.
The request object contains metadata about the request, for example what HTTP request method used, The IP address of the client etc. You find the list of HttpRequest here
Also from the documentation.
Once one of the URL patterns matches, Django imports and calls the
given view, which is a Python function (or a class-based view). The
view gets passed the following arguments:
An instance of HttpRequest.
If the matched URL pattern contained no named groups, then the matches
from the regular expression are provided as positional arguments.
The keyword arguments are made up of any named parts matched by the
path expression that are provided, overridden by any arguments
specified in the optional kwargs argument to django.urls.path() or
django.urls.re_path().
Each view function takes an HttpRequest object as its first parameter, which is typically named request

GCP authorized session get method using python 3

Attempting to use GCP Authorized Session get method in Python to query data in GCP. The doc shows:
get(url, **kwargs)
Sends a GET request. Returns Response object.
Parameters:
url – URL for the new Request object.
**kwargs – Optional arguments that request takes.
Return type:
requests.Response
I set up a kwarg dict as kwargs = {'page_size': 2000'}
However, when I passed it to the call authsess.get('someurl', kwargs), I get the following error...
TypeError: get() takes 2 positional arguments but 3 were given.
It works fine using just the url, but, I will need to add parms (specifically a nextPageToken as if one is returned)
Can someone please give me a little guidance on what I am missing here? Do I need to encode the url and parms together? or? I have tried various options here, but, just can't get it to work and not sure yet just 'how' to interpret/implement what I find in the doc for making http requests...
Thanks in advance.
OK, sorry if I wasted anyone's time. The answer is that I needed to add 'params=' to the beginning of the parameters string... i.e., authsess.get('someurl', params=kwargs)
Really wish that had been mentioned in the doc....

Django reverse routes - two optional parameters

I have a question about Django and it's routing system. I believe that it can be powerfull, but right now I am struggling with one issue I don't experience when working in other frameworks and I can't seem to get a grip on it. Worth to mention that I don't have much experience with Django at this point.
The issue is simple - I have a view which takes two optional parameters, defined like this
def test_view(id=None, grid=None):
Both parameters are optional and frequently are not passed. Id can only be an integer and grid will never be an integer (it is a special string to control datagrid when I don't want to use sessions). I have a route defined like this:
url(a(r'^test_view (\/(?P<id>\d+))? (\/(?P<grid>[^\/]+))? \/?$'), views.test_view, name='test_view'),
This works great and I am not having trouble with using one-way routes. But when I try to use the reverse function or url template tag, following error occurs:
Reverse for 'test_view' with arguments '('20~id~desc~1',)' and keyword arguments '{}' not found.
In this example I tried to find reverse without the id, just with the grid parameter. I have tried various methods of passing parameters to the reverse function:
(grid, )
(None, grid)
('', grid)
{id=None, grid=grid}
All of them result in same error or similliar one.
Is there a way to implement this in django? Maybe just disable the cool URL for the grid parameter. That is how I do it in for example Nette framework for PHP, isntead of having an url like this: 'localhost/test_view/1/20~id~desc~1' I have url like this: 'localhost/test_view/1?grid=20~id~desc~1'. This would be completely sufficient, but I have no idea how to achive this in Django.
As you note in your question, the best way to achieve this is to use standard GET query parameters, rather than doing it in the path itself. In Django you do that exclusively in the view; the URL itself is then just
url(r'^test_view$', views.test_view, name='test_view'),
and you request it via localhost/test_view?id=1&grid=20~id~desc~1. You get the params from request.GET, which is a dictionary-like object; you can use .get so that it does not raise a KeyError when the key is not provided.
def test_view(request):
id = request.GET.get('id')
grid = request.GET.get('grid')

Flask redirect to url with multiple slashes

I have a flask route like this:
#app.route('/foo/<var1>/<var2>')
def foo(var1, var2):
And later on, I try to do this:
return redirect(url_for('foo/bar/baz'))
This gives me
werkzeug.routing.BuildError
BuildError: ('foo/bar/baz', {}, None)
I've looked around and found no solutions, I've also tried things like
return redirect(url_for('foo'), var1='bar', var2='baz')
But I get the same error. Can anyone help me figure out how to properly redirect to this route?
url_for takes the function name as well as keyword arguments.
In your case, redirect(url_for('foo', var1='bar', var2='baz')) should work.
Note that what I have provided is different than the last example you provided.

Linkedin API for python

I used this library to make API requests and got the access tokens successfully.
But the documentation does not explain how _access_token and _access_token_secret should be used afterwards future. I suppose that there should be a method like:
set_access_token(_access_token, _access_token_secret)
but I could't find a method like that in this code or documentation.
Please help me to solve this problem.
I have not used this particular library or API, but a common pattern in these cases is that you pass the token as an argument to subsequent calls. Looking at the source, I can see a function called get_user_profile in __init__.py:
def get_user_profile(self, access_token, selectors=None, headers=None, **kwargs):
"""
Get a user profile. If keyword argument "id" is not supplied, this
returns the current user's profile, else it will return the profile of
the user whose id is specificed. The "selectors" keyword argument takes
a list of LinkedIn compatible field selectors.
"""
So I'd guess you just want to pass the token as the first argument (in this instance).

Categories

Resources