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.
Related
I am trying to make some tests in which asks for ads of a particular type
for instance:
http://127.0.0.1:8000/ads/?type=normal should return the normal ads
and
http://127.0.0.1:8000/ads/?type=premium should return the premium ads
the tests ask for the ads like this response = self.client.get(reverse("ads")) self.client is for the site.
Reverse() was the function i have been using for the other tests so i thought it would work as fine.
i was looking for a way i could send the parameters but there is nothing on the internet as far as i'm concerned and i have been struggling with this for hours.
┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻
If you need any more info i could bring you
i tried using:
reverse("ads", kwargs={"type": "normal"})
reverse("ads", QUERY_PARAMS={"type": "normal"})
reverse("ads", QUERY_KWARGS={"type": "normal"})
reverse("ads", {"type": "normal"})
These are all things I found online.
However, nothing worked.
When a URL is like domain/search/?q=haha, you would use request.GET.get('q', '').
q is the parameter you want, and '' is the default value if q isn't found.
However, if you are instead just configuring your URLconf**, then your captures from the regex are passed to the function as arguments (or named arguments).
Such as:
(r'^user/(?P<username>\w{0,50})/$', views.profile_page,),
Then in your views.py you would have
def profile_page(request, username):
# Rest of the method
I know that sessions are available through html templates like so:
<h1>{{session.name}}</h1>
That worked for a while but when I wanted to add more attributes to a user like an about text, I couldn't store everything in the session. The email and password I do store in the session because they are actually used. I can retrieve a user with the email and get the name like so:
User.query.filter_by(email=session['email']).first().name
However, when I try putting it into html like this it says that Users is undefined.
<li>Name: {{Users.query.filter_by(email=session['email']).first().name}}</li>
I guess some things like that are not carried over but is there a straightforward way to get all variables from the main.py file I was using there?
I even tried doing
return redirect(url_for('user', \
usr=Users.query.filter_by(email=session['email']).first().__dict__))
in main.py and then doing
<li class="list-group-item">Name: {{usr['name']}}</li>
but that wouldn't work either for some reason. What is going on?
The first solution I tried doesn't work because Flask doesn't have a reference to Users. The second doesn't work either because I passed it through url_for and not the actual render template function so it wouldn't know what to do with it.
My final solution would be this:
usr = Users.query.filter_by(email=session['email']).first().__dict__
return render_template('user.html', name=usr['name'], status=usr['status'],
about=usr['about'])
I could also just have passed the entire dict as before I believe.
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')
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()
Well i've this in my flask app :
#app.route("/changeip/<ip>")
def change_ip(ip) :
return ip
Now if i invoke it like :
http://127.0.0.1:5000/changeip?ip=1.2.2.2
It spits out "URL not found"...what is that i'm doing wrong here?
The first route describes a url with a value as part of the url. The second url describes a route with no variables, but with a query parameter in the url.
If you are using the first route, the url should look like http://127.0.0.1/changeip/1.2.2.2.
If you are using the second url, the route should look like /changeip, the function should be def change_ip():, and the value should be read from request.args['ip'].
Usually the route should describe any arguments that should always be present, and form or query params should be used for user-submitted data.
You should use:
app.route('/something/<ip>')
def function(ip):
And when you are using url_for, you should pass value of ip aswell:
url_for('function', ip='your_ip_address')
The accepted answer is correct, but I wanted to add the method that it appears the OP was originally trying in his http request.
Another way to pass in variables is through the question mark that separates variables in the url, and using requests.
import requests
Then in the method,
#app.route("/changeip")
def change_ip():
return requests.args.get('ip', '')
For the url, you pass the variable in using the question mark delimiter, the way you were originally trying.
http://127.0.0.1:5000/changeip?ip=1.2.2.2