how to write GAE search query using date?
This is my data store.
Class Property(db.Model):
createdDate=db.DateTimeProperty(auto_now_add=True)
i want to display the records in last sevendays. am tring this,
sevendays = datetime.now() - timedelta(hours=168)
getting correct result for date(7days), and i passed search query in my URL like this,
<a href="/search?search=PropertyCaseType+%3D+Enquiry+AND+PropertyStatus+%3D+Open+AND+createdDate+%3E+sevendays" class="list-group-item">
<i class="fa fa-question-circle fa-fw"></i> New Enquires
<span class="pull-right text-muted small"><em>
{% if countEnquiryOpen %}
{{ countEnquiryOpen }}
{% else %}
0
{% endif %}
</em>
</span>
</a>
above href= encode query is :
PropertyCaseType = Enquiry AND PropertyStatus = Open AND createdDate > sevendays
createdDate > sevendays is not working , otherwise query working fine and getting correct results.
how to do this , friends help me
I got the solution.. The problem is Time. So i remove time filter only date. like this,
sevendays = datetime.now() - timedelta(hours=168)
sevendays = sevendays.date()
Now i get correct result. :)
It is a bit hard to work out what is wrong with your app, as you don't show how are using the query string to construct a query.
However, a likely source of the problem could be that you are trying to compare a date string, rather than a datetime object to the createdDate property.
E.g.
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
all_props = Property.all().run()
self.response.out.write("ALL Properties\n")
for d in all_props:
self.response.out.write('Prop: %s\n' % d.createdDate)
sevendays = datetime.now() - timedelta(hours=168)
res = Property.gql('where createdDate > :1', sevendays)
self.response.out.write("MATCHING Properties compared by datetime\n")
for d in res:
self.response.out.write('date: %s\n' % d.createdDate)
self.response.out.write("MATCHING Properties compared by string\n")
sds = str(sevendays)
res_bad = Property.gql('where createdDate > :1', sds)
for d in res_bad:
self.response.out.write('date: %s\n' % d.createdDate)
will print out the correct properties under MATCHING Properties compared by datetime, but not under MATCHING Properties compared by string. Unfortunately it doesn't raise any errors either, to tell you that you are using the wrong kind of object in the query.
Therefore, if you are using the query string straight as it is passed in the url, you may need to parse it into a datetime object first using e.g. datetime.strptime().
You should build an index using only the elements from the last 7 days, then query that index and rebuild index accordingly. You can read about indexing in google app engine here.
Related
Please excuse my code, I am still a relative beginner trying to complete a school project! Basically, I am trying to create a language learning system where you input a word and it checks if it is correct. However, on the page learn.html all of the words in my database are coming up. I want to get it so that when you load the page there is the first word and when you click the button it checks that word, allowing the page to display the next word to translate. An example of this would be memrise, this screenshot shows the kind of system that I am trying to emulate.
I know that this is because of the for loop but I have tried lots of solutions to no success. It seems like a really easy problem but I am really stuck. I have 0 JavaScript expertise so if possible I would try to stay away from JS solutions. I will really appreciate any help possible :)
learn.html
{% block content %}
<form class = "form" id="form1" action="/learn/check" methods=["POST"]>
<td>
<h5> Please enter the spanish for : {% for word in course_content %}{{ word.english }} {% endfor %} </h5>
<input type="text" name="language_learning_input" id="desc" value="" size="100" maxlength="140"/>
<p> </p>
</td>
<input type="submit" name="button" class="btn btn-success" value="Update"/>
</form>
{% endblock content %}
snippet of main.py
#LEARN SYSTEM
#STORING DB VALUES IN LISTS
def spanish():
#setting variables
holding_spanish = []
#running db query
course_content = db.session.query(Course).all()
#iterating through db
for row in course_content:
holding_spanish.append(row.spanish)
return holding_spanish
def english():
#setting variables
holding_english = []
#running db query
course_content = db.session.query(Course).all()
#iterating through db
for row in course_content:
holding_english.append(row.english)
return holding_english
def score():
#setting variables
holding_score = []
#running db query
account_settings = db.session.query(AccountSettings).all()
#iterating through db
for row in account_settings:
holding_score.append(row.words_per_lesson)
return holding_score
#MAIN LEARN PAGE
#app.route("/learn")
def learn():
#getting values
english()
spanish()
score()
x=1
testingvalue = [score()]
acccount_settings = db.session.query(AccountSettings).all()
course_content = db.session.query(Course).all()
return render_template('learn.html', course_content=course_content, acccount_settings=acccount_settings,testingvalue=testingvalue,x=x,english=english)
#ROUTE USED TO CHECK
#app.route("/learn/check", methods =['GET'])
def learncheck():
course_content = db.session.query(Course).all()
language_learning_input = request.args.get('language_learning_input')
for row in course_content:
if language_learning_input == row.spanish:
"<h1> correcto! </h1>"
print("true")
else:
"<h1> not correcto! :</h1>"
print("false")
Basically you need to understand two things.
First, of the many words you have to return only one. *
So, how do you know which word the user has already seen?
You don't. HTTP is a stateless protocoll. That means, each request (access by a browser) is independent of another one.
But you can work around this limitation.
So, second, you need to save the state. And there are several concepts.
From the top of my head, you could use
sessions
cookies
or pass a parameter with e.h. the current word, so you can deduct the next word
That's it. Enjoy your homework and do not hesitate to create a new question when you encounter a specific problem
You could also return all words, and then do the cycling through the words via Javascript.
Similar question which does not solve my problem.
I have a Flask app which reads from a database and renders an HTML template using the DB data. I'm trying to manipulate a value I get from the DB before sending it to the HTML template and this doesn't work.
Python code:
#app.route('/pilot', methods=['GET'])
def form_view():
result = {}
# query DB and get cursor
numQuestions = 0
for row in cursor:
row.pop('_id', None) # delete the key and add modified key back
row['_id'] = row['stage'][-1] # get only last char- eg, "1" from "stage1", "2" from "stage2" and so on
print(row['_id'])
result[numQuestions] = row
numQuestions += 1
return render_template("form.html", count=numQuestions, result=result, debug=app.debug)
Output when run on terminal is as expected:
1
1
1
2
2
2
Jinja2 fragment of form.html:
{% for row in result[row_num]['scrutiny_stage'] %}
{{ row['_id'] }}
{% endfor %}
Output on browser:
stage1 stage1 stage1 stage2 stage2 stage2 stage2
Can anyone help me understand what I'm doing wrong here and how I can get the correct value of the variable I'm setting in the Python code to show up in the HTML template being rendered by Flask?
Thanks.
Thanks for the tips folks, even though I couldn't share all the context (since I have to protect proprietary info), they were helpful. I managed to solve this with multiple steps:
I redid my DB schema so that every document has an '_id' key with a plain numeric value. I dropped the 'stage': 'stage1' kinds of fields. The 'stage' is now computed dynamically in the code base on the DB query results.
Then I changed the Flask view function to add a 'stage' key to the result dict being passed to the HTML template (no mucking around with the '_id' field):
numQuestions = 0
for row in cursor:
for line in row['scrutiny_stage']:
row['stage'] = line['_id']
result[numQuestions] = row
numQuestions += 1
Finally, in my Jinja2 block, I realized that I need to operate over the result as a dict, so I changed it to use the dict.values() method:
{% for row in result.values() %}
{{ row['stage'] }}
{% endfor %}
Now, I get the same values printed in the terminal as well as in my browser.
Is there a function like trim() in python?
i use Flask miniframework and it doesn't accept:
selected_student = (request.args.get('student_form')).strip()
its error: AttributeError: 'NoneType' object has no attribute 'strip'
selected_student.replace(" ", "")
its error: AttributeError: 'NoneType' object has no attribute 'replace'
i need a function like trim() without coding a class/subclass or javascript
You're seeing the errors that you are seeing because there is no data being passed from your form to the Flask server. Your use of request is returning a None value type as opposed to a str.
You posted the following HTML mark up for your form:
<form action="/student" method='POST'>
<select name="student_form ">
{% for student in students_list %}
<option value="{{student}}">{{student}}</option>
{% endfor %}
</select>
<input type='submit' value='submit' />
</form>
So therefore you're going to need somewhere for Flask to pick up this data on the server side, for example:
#app.route('/student', methods=['POST'])
def receive_student_form_data:
my_selection = str(request.form.get('student_form')).strip()
print(my_selection)
Just to clarify why I've made my method in this way: I notice that you're using request.args.get() in order to retrieve the value sent by the form. This is incorrect.
request.args is used to retrieve key / value pairs from the URL.
request.form is used to retrieve key / value pairs from a HTML form.
So I'd suggest that you should use request.form.get('student_form') instead. If you really want to be certain that it is being cast as a str when retrieved by your Flask server, then you can cast it as a str as follows:
str(request.form.get('student_form'))
Then, as has been suggested by a few people already, you can use the .strip() method to remove any trailing spaces.
There is a strip() method. The error you get is because you are trying to run it on a NoneType object. You need to run it on a string object.
>>> s = 'some string '
>>> s.strip()
'some string'
There is also replace for strings:
>>> s.replace('some', 'many')
'many string '
The issue you encounter is related to something else. You end with a None object instead of what you are trying to get.
update 0:
There is a subtle, but serious, error in my code and in my explanation below because I cannot only compare the name on the template with the hiddenname on the template (that much only tells me that the user has made a change like a checkbox change would tell me, but purposely there are no checkboxes), I also need to compare name to the status of name in the datastore of reservations to see if someone else has already reserved the time slot. So I cannot use javascript and I have to rewrite some of the code below to make the correct comparison, too. And may original question remains as suggested by the Title of this question. (In one of the comments I erroneously said that javascript would work.)
update 0:
I am trying to write a sort of "alert" in the way that this code suggests where I use the Trans model and the gae datastore (further below) to communicate between my main app and the "alert template". I have a few problems.
Initially I had my need for this alert in an another part of my code in an else: clause, not in an elif: clause. When I tried to use the simpler version of my alert in the elif code, python seemed to ignore the self.response.out.write(template.render(path, template_values)) and just went on to this code which ended my conditionals: return webapp2.redirect("/read/%s" % location_id). So, as you can see in my code I have commented out the ignored former code line and attempted to replace it with something more like the latter code line, but with that latter line directed to unexpected instead of read. You can see from my code it is still a mix between the two approaches and I could use help sorting that out. Is there really something different about else: and elif: regarding this?
Originally I had not anticipated my desire to call the same html template and Trans model from so many places in my code, so I did not design a key or ID or key_name into the design of using Trans. And now I am having trouble implementing a version with such detail.
I have been looking for an example of how such "alert templates" can be made in python. They are so easy in javascript, but I am trying to do the user input validation in my python code. Any pointers to examples or docs would be greatly appreciated.
weekday_key = db.Key.from_path('Locations',location_id,'Courts', court_id,'Days',weekday)
if name == hiddenname:
pass
elif name != hiddenname and hiddenname == "":
reservation = Reservations.get_or_insert(time[2],parent=weekday_key)
reservation.hour = time[0]
reservation.minute = time[1]
reservation.year = int(year)
reservation.nowmonth = int(nowmonth)
reservation.day = int(day)
reservation.nowweekday = int(nowweekday)
reservation.name = name
reservation.put()
elif name != hiddenname and name!="":
reservation = Reservations.get_by_key_name(time[2],parent=weekday_key)
reservation.hour = time[0]
reservation.minute = time[1]
reservation.year = int(year)
reservation.nowmonth = int(nowmonth)
reservation.day = int(day)
reservation.nowweekday = int(nowweekday)
reservation.name = name
reservation.put()
reason='This was in that time slot already: '
trans = Trans(parent=reservation.key().name()) #this line is iffy
trans.reason=reason
trans.name=hiddenname
trans.put()
iden = trans.key().id() # this is part of the iffy just above
template_values = {'trans':trans}
path = os.path.join(TEMPLATE_DIR, 'unexpected.html')
#self.response.out.write(template.render(path, template_values))
return webapp2.redirect("/unexpected/%s/%d" % (time[2],iden) #more iffy
else:
pass
My model for Trans in next.
class Trans(db.Model):
reason = db.StringProperty()
name = db.StringProperty()
My jinja2 equipped unexpected.html template is as follows.
{% extends "base.html" %}
{% block content %}
This unexpected result occurred. {{ trans.reason }}:<emph style="font-weight: bold">{{ trans.name }}</emph>
<br /><br />
<div id="inputdata">
<label>Click the "Ok" button to go back to the previous page so you can elect to edit your entry, or not.
</label>
<button onclick="window.history.back()">Ok</button>
</div>
{% endblock content %}
This question is answered here. It could have been answered in this question, but apparently there was too much information given and no one saw the answer.
Using Jinja2, how do I format a date field? I know in Python I can simply do this:
print(car.date_of_manufacture.strftime('%Y-%m-%d'))
But how do I format the date in Jinja2?
There are two ways to do it. The direct approach would be to simply call (and print) the strftime() method in your template, for example
{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}
Another, sightly better approach would be to define your own filter, e.g.:
from flask import Flask
import babel
app = Flask(__name__)
#app.template_filter()
def format_datetime(value, format='medium'):
if format == 'full':
format="EEEE, d. MMMM y 'at' HH:mm"
elif format == 'medium':
format="EE dd.MM.y HH:mm"
return babel.dates.format_datetime(value, format)
(This filter is based on babel for reasons regarding i18n, but you can use strftime too). The advantage of the filter is, that you can write
{{ car.date_of_manufacture|format_datetime }}
{{ car.date_of_manufacture|format_datetime('full') }}
which looks nicer and is more maintainable. Another common filter is also the "timedelta" filter, which evaluates to something like "written 8 minutes ago". You can use babel.dates.format_timedelta for that, and register it as filter similar to the datetime example given here.
Here's the filter that I ended up using for strftime in Jinja2 and Flask
#app.template_filter('strftime')
def _jinja2_filter_datetime(date, fmt=None):
date = dateutil.parser.parse(date)
native = date.replace(tzinfo=None)
format='%b %d, %Y'
return native.strftime(format)
And then you use the filter like so:
{{car.date_of_manufacture|strftime}}
I think you have to write your own filter for that. It's actually the example for custom filters in the documentation.
If you are dealing with a lower level time object (I often just use integers), and don't want to write a custom filter for whatever reason, an approach I use is to pass the strftime function into the template as a variable, where it can be called where you need it.
For example:
import time
context={
'now':int(time.time()),
'strftime':time.strftime } # Note there are no brackets () after strftime
# This means we are passing in a function,
# not the result of a function.
self.response.write(jinja2.render_template('sometemplate.html', **context))
Which can then be used within sometemplate.html:
<html>
<body>
<p>The time is {{ strftime('%H:%M%:%S',now) }}, and 5 seconds ago it was {{ strftime('%H:%M%:%S',now-5) }}.
</body>
</html>
You can use it like this in template without any filters
{{ car.date_of_manufacture.strftime('%Y-%m-%d') }}
Google App Engine users : If you're moving from Django to Jinja2, and looking to replace the date filter, note that the % formatting codes are different.
The strftime % codes are here: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
You can use it like this in jinja template
{{ row.session_start_date_time.strftime('%d-%m-%Y %H:%M:%S')}}
In this code the field name is row.session_start_date_time.
in flask, with babel, I like to do this :
#app.template_filter('dt')
def _jinja2_filter_datetime(date, fmt=None):
if fmt:
return date.strftime(fmt)
else:
return date.strftime(gettext('%%m/%%d/%%Y'))
used in the template with {{mydatetimeobject|dt}}
so no with babel you can specify your various format in messages.po like this for instance :
#: app/views.py:36
#, python-format
msgid "%%m/%%d/%%Y"
msgstr "%%d/%%m/%%Y"
I use this filter, it's in Spanish but you may change the names as you need.
#app.template_filter('datetime')
def date_format(value):
months = ('Enero','Febrero',"Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
month = months[value.month-1]
hora = str(value.hour).zfill(2)
minutos = str(value.minute).zfill(2)
return "{} de {} del {} a las {}:{}hs".format(value.day, month, value.year, hora, minutos)
There is a jinja2 extension you can use just need pip install (https://github.com/hackebrot/jinja2-time)