How to handle HTML Arrays with App Engine Python? - 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)

Related

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

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.

How to pass a python list of URLs to a Django template and make them clickable?

I have a python list of urls which looks like this:
list = ['/abc/1',
'/abc/3',
'/abc/5',
...
]
all these urls follow the url pattern 'abc/n/' which I have defined in urls.py.
now I want to pass this list to a django template in such a way that each element of this list becomes clickable and runs the function corresponding to their url pattern on clicking them.
I tried hardcoding the anchor tag to each element of this list. for example
for i in range (len(list)):
list[i] = "<a href = \'" + list[i] + "\'>click me</a>"
and then sending this list to template via HttpResponse() function via a context. But this displayed the list items in raw text format instead of links
What is happening here is that django is being safe and escaping your html. This is to prevent XSS vunerabilities. This is a vulnerability that happens when e.g. users can insert malicious HTML into your site.
Now, you could turn that off, but then you risk having the aforementioned security issues.
What you will want to do instead is generate the html in the template, not in your code (that's what templates are there for):
{% for link in links %}
click me
{% endfor %}
Now you just need to pass links in your template context!
Instead of using a for loop format the links as html, just pass the list directly into your context then within your django template use:
{% for item in list %}
Link text
{% endfor %}
If your links are not all going to be placed on the page consecutively, you can just use:
{{ list.index }}
with index being the index of the item you wish to access

Can make a Search with a template form work

I use crispy-forms in all of my search,but in this one I need to do it with a template form, I don't know what's wrong with my code 'cause I have the same code in other project and it works fine, I don't know if is the Django version, currently I'm using 1.8. The error that I get is Page not found (404), I doesn't find the url.Here's my code hope you can help me. I use q and param in the url but none works.
urls.py
url(r'^search/(?P<param>\S+)$', permission_required('agenda.change_agenda', login_url='/no_access')(SearchContact.as_view()), name='searchcontact'),
template_form.html
<form class="well form-search" action="/search/" method="get">
<input type="text" class="input-medium search-query" name="param">
<button type="submit" class="btn">Search</button>
</form>
views.py
class SearchContact(ListView):
template_name = 'agenda_contacts.html'
def get_queryset(self):
query = self.request.GET.get('param')
return Agenda.objects.filter(name=param)
Your regex
r'^search/(?P<param>\S+)$
matches urls like /search/hello or /search/my-search.
However, your search form is sending the search terms in the GET paramters, for example /search/?param=hello or /search/?param=my-search.
GET parameters are not captured in urls.py. You can access them with request.GET in the view as you are already doing.
Therefore, you should remove param from the regex, and change your url pattern to the following.
url(r'^search/$', permission_required('agenda.change_agenda', login_url='/no_access')(SearchContact.as_view()), name='searchcontact'),

How to use hidden input in an html form with Python+Jinja2

When I put this line in my html template, I can successfully pass the input string via a jinja2 variable into my Python code...
<label for="firstName">First name*</label>
<input type="text" name="fname" id="firstName" value="{{ fname }}">
However, when I attempt to pass a hidden input with the following line...
<input type="hidden" name ="contact_form" value="{{ active_form }}">
... I'm not seeing the value pass back to my Python code. I've not learned Javascript yet. Is there some Javascript required to pass hidden input values? What am I missing?
I recommend using WTForms.
Example
from wtforms import TextField, validators, PasswordField, TextAreaField, HiddenField
class ArticleCreateForm(Form):
title = TextField('Title', [validators.Required("Please enter title.")],
filters=[strip_filter] )
body = TextAreaField('Body', [validators.Required("Please enter body.")],
filters=[strip_filter])
category = QuerySelectField('Category', query_factory=category_choice )
person_name = HiddenField()
views.py
#app.route('/create', methods=['GET', 'POST'])
def article_create():
if 'email' not in session:
return redirect(url_for('signin'))
person = Person.query.filter_by(email=session['email']).first()
name = person.firstname
article = Article()
form = ArticleCreateForm()
form.person_name.data = person.firstname
if form.validate_on_submit():
form.populate_obj(article)
db.session.add(article)
db.session.commit()
return redirect(url_for('index'))
return render_template('create.html', form=form, person=person, name=name)
I know this is an old post but I was fooling around with a Jinja template and I wanted solve this particular issue since I was dealing with it myself. I was planning on fooling Jinja by passing in my value and adding the quote symbols (") in a concatenated string along with my Jinja variable (named "ticket_number") like so:
<input class="hidden" name="ticket_number" value={{ ticket.ticket_number + '"' }}>
That will NOT work. So I removed the concatenation and passed the variable in directly. This seemed promising. Was expecting to find the HTML code would contain the variable value without the quote symbols surrounding up but was presently surprised to find that either Jinja or Flask quoted the variable correctly with no extra add on's using the straight variable value:
<input class="hidden" name="ticket_number" value={{ ticket.ticket_number }}>
The variable itself is an integer so I confirmed if this also happens with regular alphanumerical string variables. Let me know if it works for you all-
If you are using Flask along with Jinja2 (which I would recommend), you can run code like this in the view function:
from flask import request
#app.route('/path/to/submit/page', methods=["GET","POST"])
def viewfunctionforsubmitpage():
request.form['contact_form']
Flask is a nice, lightweight, and built using Jinja2, so that is good.

Google app engine ReferenceProperty relationships

I'm trying to get my models related using ReferenceProperty, but not have a huge amount of luck. I have 3 levels: Group, Topic, then Pros, and Cons. As in a Group houses many topics, and within each topic could be many Pros and Cons.
I am able to store new Groups nice and fine, but I don't have any idea how to store topics underneath these groups. I want to link from a page with a link "New topic" underneath each group, that takes them to a simple form (1 field for now). Obviously the URL will need to have some sort of reference to the id of the group or something.
Here are my models:
class Groups(db.Model):
group_user = db.UserProperty()
group_name = db.StringProperty(multiline=True)
group_date = db.DateTimeProperty(auto_now_add=True)
class Topics(db.Model):
topic_user = db.UserProperty()
topic_name = db.StringProperty(multiline=True)
topic_date = db.DateTimeProperty(auto_now_add=True)
topic_group = db.ReferenceProperty(Groups, collection_name='topics')
class Pro(db.Model):
pro_user = db.UserProperty()
pro_content = db.StringProperty(multiline=True)
pro_date = db.IntegerProperty(default=0)
pro_topic = db.ReferenceProperty(Topics, collection_name='pros')
class Con(db.Model):
con_user = db.UserProperty()
con_content = db.StringProperty(multiline=True)
con_date = db.IntegerProperty(default=0)
con_topic = db.ReferenceProperty(Topics, collection_name='cons')
And one function for the actual page I want to show the list of Groups, and then underneath their topics:
class Summary(webapp.RequestHandler):
def get(self):
groups_query = Groups.all()
groups = groups_query.fetch(1000)
template_values = {
'groups': groups,
}
path = os.path.join(os.path.dirname(__file__), 'summary.html')
self.response.out.write(template.render(path, template_values))
And finally the html:
<html>
<body>
New Group
<br>
{% for group in groups %}
<font size="24">{{ group.group_name|escape }}</font><br> by <b>{{ group.group_user }}</b> at <b>{{ group.group_date }}</b> {{ group.raw_id }}
<br>
<a href="/newtopic?id={{group.key.id}}" >New topice </a>
<br>
<blockquote>
{{ topics.topics_name }}
</blockquote>
{% endfor %}
</body>
</html>
Something that has side effects, such as altering the store (by creating a new object for example) should NOT be an HTTP GET -- GET should essentially only do "read" operations. This isn't pedantry, it's a key bit of HTTP semantics -- browsers, caches, proxies, etc, are allowed to act on GET as read-only operations (for example by caching results and not passing a request to the server if they can satisfy it from cache).
For modifications, use HTTP verbs such as POST (most popular essentially because all browsers implement it correctly) or for specialized operations PUT (to create new objects) or DELETE (to remove objects). I assume you'll be going to use POST to support a variety of browsers.
To get a POST from a browser, you need either Javascript wizardy or a plain old form with method=post -- I'll assume the latter for simplicity.
If you're using Django 1.0 (which app engine supports now), it has its own mechanisms to make, validate and accept forms based on models. Other frameworks have their own similarly advanced layers.
If you want to avoid "rich" frameworks you'll have to implement by hand templates for your HTML forms, direct them (via some kind of URL dispatching, e.g. in app.yaml) to a handler of yours implementing with a def post(self):, get the data from the request, validate it, form the new object, put it, display some acknowledgment page.
What part or parts of the procedure are unclear to you? Your question's title focuses specifically on reference properties but I'm not sure what problem they are giving you in particular -- from the text of your question you appear to be on the right tack about them.
Edit: the OP has now clarified in a comment that his problem is how to make something like:
"<a href="/newtopic?id={{group.key.id}}" >New topic </a>"
work. There's more than one way to do that. If the newtopic URL is served by a static form, the handler for the post "action" of that form could get back to that id= via the Referer: header (a notorious but unfixable mis-spelling), but that's a bit clunky and fragile. Better is to have the newtopic URI served by a handler whose def get gets the id= from the request and inserts it in the resulting form template -- for example, in a hidden input field. Have that form's template contain (among the other fields):
<INPUT TYPE=hidden NAME=thegroupid VALUE={{ theid }}> </INPUT>
put theid in the context with which you render that template, and it will be in the request that the def post of the action receiving the form finally gets.
Just to answer the question for others as you probably figured this out:
class NewTopic(webapp.RequestHandler):
def get(self):
groupId = self.request.get('group')
# either get the actual group object from the DB and initialize topic with topic_group=object as in 'Nick Johnson's answer, or do as follows
topic = Topic()
topic.name = self.request.get("topicname")
topic.reference = groupId
topic.put()
Thankyou for the reply.
Yeah I am aware of the get vs post. The class I posted was just to actually print all the Groups().
The issue I have is I'm unsure how I use the models to keep data in a sort of hierarchical fashion, with Groups > Topics > Pros/Cons.
Grabbing data is simple enough and I am using:
class NewGroupSubmit(webapp.RequestHandler):
def post(self):
group = Groups()
if users.get_current_user():
group.group_user = users.get_current_user()
group.group_name = self.request.get('groupname')
group.put()
self.redirect('/summary')
I need another function to add a new topic, that stores it within that group. So lets say a group is "Cars" for instance; the topics might be "Ferrari", "Porsche", "BMW", and then pros/cons for each topic. I realise I'm being a little vague, but it's because I'm very new to relational databasing and not quite used to the terminology.
I'm not quite sure what problem you're having. Everything you list looks fine - the ReferenceProperties are set up according to what one would expect from your dscription. The only problem I can see is that in your template, you're referring to a variable "topics", which isn't defined anywhere, and you're not iterating through the topics for a group anywhere. You can do that like this:
<html>
<body>
New Group
<br>
{% for group in groups %}
<font size="24">{{ group.group_name|escape }}</font><br> by <b>{{ group.group_user }}</b> at <b>{{ group.group_date }}</b> {{ group.raw_id }}
<br>
<a href="/newtopic?id={{group.key.id}}" >New topice </a>
<br>
Topics:
<ul>
{% for topic in group.topics %}
<li>{{topic.topic_name}}</li>
{% endfor %}
</ul>
{% endfor %}
</body>
</html>
To create a new topic, just use the constructor, passing in the required arguments:
mytopic = Topic(topic_name="foo", topic_group=somegroup)
Here, somegroup should be either a Group object, or a key for a Group object.

Categories

Resources