Sending Flask variable from HTML back to Flask with url_for() - python

I'm trying to create a little job board, each job card is dynamically inserted from flask from a list (for now, will be an SQL DB later)
When the user clicks the button View Task I want it to go to another page where it displays the task/job in more detail.
What I want attached to that button is the job/task ID.
This is how I'd want/expect the button to function
{% for task in available_tasks %}
<div>
View Task
</div>
{% endfor %}
This could then be pasted into a route that would take the ID as an argument and fetch the full job/task information.
app.route('/view_task/<task_id>')
def view_task(task_id):
task_data = task_database[taskid]
return render_template('detailed_view.html', task_info=task_data)
My problem is href="url_for('view_task', task_id={{ task['id'] }})" doesn't work, is there a way to do this?

You generated the output href="url_for('view_task', task_id=<some id>)", so the literal text url_for(..) is in the HTML generated and delivered to your browser, and HTML engines don't recognise that string as a valid URL for anything.
You need to put the url_for() function in the {{ ... }} brackets, not just the task id value:
href="{{ url_for('view_task', task_id=task['id']) }}"
Only then is url_for() actually treated as an expression for Jinja2 to execute, at which point the HTML produces will contain the href="http://localhost:5000/view_task/<some id>" string.

Related

Button click in HTML to update SQLAlchemy db in Flask

I'm trying to update a database value called ''favorites'' for the logged in user of a Flask web app using a button click. Essentially, the favorites column is a single string that looks like this: Apples, Bananas, Oranges where on the button click, I would want to append a value (say Cherries) by breaking apart the string into a list in my #app.routes(), appending the value, and rejoining it back into a string before committing the changes. I'm not sure what the proper way is to do this, here's what I have:
HTML snippet
<button action="{{ url_for('add') }}" method="post" type="submit">Favorite</button>
#app.routes()
#app.route('/add', methods=['POST'])
def add():
star_faves = current_user.favorites
star_faves_list = star_faves.split(', ')
star_faves_list.append('Cherries')
', '.join(star_faves_list)
current_user.favorites = star_faves_list
db.session.commit()
return render_template('add.html')
The problem is that I don't really understand how the HTML is communicating with Python/Jinja, if anybody can help clear that up I would greatly appreciate it.
It looks like you have some elements confused.
If you want to submit a POST request to the /add page, the easiest way is to create a form. (Buttons do not have an action or method attribute, forms do.) When you create the form, you also specify the HTTP method to use when submitting the form. So in your case, it should look something like this:
<form action="{{ url_for('add') }}" method="POST">
<input type="submit" value="Favorite">
</form>
You can use a button instead of an input with type submit, they are interchangeable.
If you don't want the page to reload while submitting the request, a more advanced technique you can use with JavaScript is something called AJAX.
This example code sends the same POST request to the /add page:
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
// this method gets called if the state of the request changes (it succeeds of fails)
// you will probably want to update your page accordingly here
};
request.open('POST', '/add');
request.send();

Create a Flask Search Bar that Inserts URI Variable with url_for()

I have a Flask site that has a 'search bar' where you type in the location ID of a particular location and then click Submit to be taken to the page for that location, if it exists. Here's the current form action:
<form id="locationinfo" action="{{ url_for('location') }}">
When you click Submit you are taken to /location?info=SITEID and that works just fine. What I want to do is change this behavior slightly so that when a user clicks Submit they are taken to /location/SITEID/ instead. I have the decorator set up in my main Flask routes file, but I'm struggling to put the pieces together to get this simple form together.
#app.route("/location/<locationid>/")
def locations(locationid):
...
return locationid
Any direction would be greatly appreciated!
[Edit with current full form code]
#app.route("/location")
def location():
location_id = request.args.get("info")
<form id="info" action="{{ url_for('location') }}">
<input type="text" name="info" id="locationfield">
<button type="submit">Go!</button>
</form>
You can't change how HTML forms submit their fields, they will always be in the query string or body (POST). One option is to use JavaScript to override the submit event to perform your own submit and re-render with the results.
A simpler solution is to redirect to the nice url after submit. This keeps the "search" action separate from the "show" action (even if they are handled by the same view).
#app.route('/location/')
#app.route('/location/<int:id>/')
def location(id=None):
# redirect to the second form if the id wasn't in the path
# raises 400 error if id wasn't in the query
if id is None:
return redirect(url_for('location', id=request.args['info']))
# id is in the path, continue
...
You can expand this later if you want to search by something besides id. Perform the search then redirect to the found id.

GET data in django urls.py not passing to view

I'm having a tough time figuring out how to parse my URL GET data and send it to the right view.
I have a search view that only has a search input:
template/search.html
<form action="http://domain.com/schools/search/" method="GET" >
<input type="text" name = "q_word">
<input type="submit" value="Search"/>
</form>
When a user enters in a search term, I want to send that data to another view to parse and use in a geocoding function I wrote. Here is a look at my urls.py:
url(r'^schools/search/$', school_views.find_school, name="find_school"),
url(r'^schools/search/(?P<address>[\w ]+)$', school_views.geo_locate, name="geo_locate"),
I want to grab the GET data from a URL (after they've entered in the info), and pass it as an address argument to my school_views.geo_locate function.
This set up works great when you manually type out a URL like: schools/search/150%20main%20Street
But when a user submits any form data, the URL passed is /schools/search/?q_word=150+west+main and I'm just kicked back to my search template.
I think my regex needs to be tweaked in my second url argument, but I just keep returning to the search page after submission, with no data going to my geo_locate view. Is this a URLs problem?
GET data is not passed in the URL parameters. Don't try to capture it in the regex. Just get it from request.GET inside the view.

Unable to access request.GET['next'] in get_login_redirect_url in Django All Auth

My form submits as follows
<form class="form-signin" role="form" action="{% provider_login_url "facebook" method="js_sdk" next="/next"%}">
I overrode the DefaultAccountAdapter with my own AccountAdapter with method
def get_login_redirect_url(self, request):
print request.GET['next']
...
But request loses the next parameter and the print returns an error because there is no "next" in request.GET.
Why can't I access the next parameter?
I was originally using get_login_redirect_url to handle different url redirects after creation of social versus username/password users. Now, I need to be able to specific the next parameter in the URL for another variant of behavior for social user login but am unable to access the next parameter because it does not seem to be passed.
I am not sure whether I could give the precise solution for your issue. But I think got the point.
To access the next parameter from url,
The url should be,
http://127.0.0.1:8000/index?next=2
If you have to form the url in this above manner,you can get access to the next argument from request object in your corresponding view method
print request.GET.get('next')
So, please make sure to format request url with proper querystring refer
To your case,
I have no idea about {% provider_login_url %} template tag
I am assuming after your tag rendered it yields the url index, then i am appending my querystring next
<form class="form-signin" role="form" action="/index?next=someValue">
you may try additionally,
{% provider_login_url "facebook" next=next %}
source
I came across with a similar problem. However, I wasn't signing in with facebook. request.GET was always empty.
I think you could try using jQuery to manually append next parameter to the action attribute of <form>. See this question. It solves my problem.

How to handle HTML Arrays with App Engine Python?

I'm stuck with this problem I made an HTML Array, but I can't read it out with Python. Is it even possible to do it in App Engine? I read it was possible in PHP.
This is the html code:
<label for="hashtags">Hashtags: </label><br/>
{% for hashtag in stream.hashtags %}
<input type="text" value="{{hashtag}}" name="hashtags[]" id="hashtags" class="text ui-widget-content ui-corner-all" />
{% endfor %}
This is how I'm currently trying to read the HTML Array:
newHashTags = self.request.get('hashtags[]')
for newHashTag in newHashTags:
stream.hashtags.append(newHashTag)
This is in the post variable when I'm debugging.
MultiDict: MultiDict([('streamid', '84'), ('name', 'Akteurs'), ('description', '#stream'), ('hashtags[]', '#andretest'), ('hashtags[]', '#saab')])
You don't need to include the [] at the end of the name of a field you'd like to treat as a list or array, that's some PHP-specific magic. Instead, just name the field hashtags and in your request handler do this to get a list of hashtags from the request:
newHashTags = self.request.get('hashtags', allow_multiple=True)
The allow_multiple=True argument will make get method return a list of all hashtags values in the request. See the relevant documentation for more info.
You could also avoid the for loop by doing something like this:
newHashTags = self.request.get('hashtags', allow_multiple=True)
stream.hashtags.extend(newHashTags)

Categories

Resources