In my Flask web app I have a login system. When user logged, in the table of my database I want to update the datetime when user made the last login.
I'm using this code:
#app.route('/login', methods=['POST'])
def do_admin_login():
POST_CODICE_FISCALE = str(request.form['codice_fiscale'])
POST_PASSWORD = str(request.form['password'])
pwd_enc=base64.b64encode(POST_PASSWORD)
Session = sessionmaker(bind=engine)
s = Session()
query = s.query(User).filter(User.codice_fiscale.in_([POST_CODICE_FISCALE]), User.password.in_([pwd_enc]))
result = query.first()
if result:
session['logged_in'] = True
query = s.query(User).filter(User.codice_fiscale.in_([POST_CODICE_FISCALE]).update(User.data_ora_ultimo_accesso=datetime.now()))
query.first()
db.session.commit()
else:
flash('wrong password!')
return home()
but I receive the error:
query = s.query(User).filter(User.codice_fiscale.in_([POST_CODICE_FISCALE]).update(User.
data_ora_ultimo_accesso=datetime.now()))
SyntaxError: keyword can't be an expression
what it is wrong?
thanks.
As the error says, a keyword in a function call argument list cannot be an expression, such as User.data_ora_ultimo_accesso, but an identifier. Instead you should pass Query.update() a dictionary of column, expression pairs:
query = s.query(User).\
filter(User.codice_fiscale.in_([POST_CODICE_FISCALE]).\
update({ User.data_ora_ultimo_accesso: datetime.now() },
synchronize_session=False))
Note that since you commit right away, there's no need to synchronize the session, since all state will be expired anyway.
You could also make some changes that'd improve your code's readability. For example instead of
filter(User.codice_fiscale.in_([POST_CODICE_FISCALE]),
User.password.in_([pwd_enc]))
just
filter(User.codice_fiscale == POST_CODICE_FISCALE,
User.password == pwd_enc)
No point in checking if a list of 1 item contains something, compared to just testing equality.
Finally, you create a new Session class and an instance s of it, but you commit a different session: db.session, which you should've probably been using all along. What this means is that your updates will not take place, as that session's transaction is not actually committed.
Related
I am creating a Python Flask application where the name of the user's account is being passed from a MySQL database into a Flask application where it can be used on webpages.
I've successfully been able to retrieve the first name from the user's credentials in the database using this:
if sha256_crypt.verify(userDetails['password'], str (data[0])):
cursor.execute("SELECT fname FROM user_details WHERE email = %s;", (email, ))
name = cursor.fetchone()
session['user'] = name
return redirect(url_for('success', name=name))
To explain what this snippet does, once the user's entered login details have been checked against the database and authorised, the query pulls the first name from the user_details table and assigns it to the name variable, to which the name is used to initiate a session.
The user is then returned to the login page (now logged in) where another variable called name (I will probably change this so it's easier to differentiate) is passed the name that is stored in the session to display on the website using this function:
#app.route('/loginpage', methods=['POST', 'GET'])
def loginpage():
if 'user' in session:
name = session['user']
return render_template('login.html', name=name, loggedOut=False, loggedIn=True)
return render_template('login.html', loggedOut=True, loggedIn=False)
This is all successfully working and retrieves the user's first name from the database, the only problem though is that when the name is displayed with {{name}} in the HTML, the name shows up as ('John',), which means for example this:
<div class="container logout-greeting">
<h5 style="text-align: center">Hello {{name}}, it appears you are logged in, click here to log out</h5>
</div>
Which should display as:
"Hello John, it appears you are logged in, click here to log out"
Is instead displaying as:
"Hello ('John,'), it appears you are logged in, click here to log out"
I've checked with someone that is more experienced with building Web Applications and they couldn't spot the issue, so is it possible anyone else could give me a pointer as to what is causing this?
cursor.fetchone() returns all the selected fields from one row as a tuple. For example, if you did something like SELECT first, last ..., you'd get a 2-tuple ("John", "Smith").
You only requested one field, so you get 1-tuple ("John",): you do not get a string "John"! Change to:
name = cursor.fetchone()[0]
EDIT: Or, as Vincent warns below, more robustly:
row = cursor.fetchone()
name = row[0] if row else None
See How to create a tuple with only one element for discussion of 1-tuples, and why there is a comma there.
cursor.fetchone() returns a tuple (similar to a list) containing all columns of the row.
Its string representation looks like this.
You can solve this by selecting the first item in the response:
values = cursor.fetchone()
if values:
name = values[0]
I am learning how to create a flask application that insert records un a mysql database whose values are obtained from an html form.
I have written the following piece of code:
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_mysqldb import MySQL
app = Flask(__name__)
#MySql Connection
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = 'password'
app.config['MYSQL_DB'] = 'flaskcontacts'
mysql = MySQL(app)
# settings
app.secret_key = 'mysecretkey'
#app.route('/')
def Index():
return render_template('index.html')
#app.route('/add_contact', methods=['POST'])
def add_contact():
if request.method == 'POST':
fullname = str(request.form['fullname'])
phone = str(request.form['phone'])
email = str(request.form['email'])
cur = mysql.connect.cursor()
print(str(fullname), phone, email)
cur.execute("INSERT INTO flaskcontacts.contacts (fullname, phone, email) VALUES (%s, %s, %s)",
(fullname, phone, email))
mysql.connection.commit()
flash('Contact Added successfully')
return redirect(url_for('Index'))
Once I execute it I see that I obtain the message "Contact added succesfully" but I cannot see any record in the mysql database, however I see that the Id that is autoincremental, it is incremented. So if I update the table directly into the database it works and shows me a number of Id that was already autoincremented, as if the previous piece of code worked but it doesn't update it at all.
I have invested many hours trying to fix this problem, but apart from the answer I would appreciate if you can help me with some best practices of how to debug these type of problems.
Regards
MySQL will generate an auto-increment ID before it tries the INSERT. But the INSERT might fail, for example if the INSERT causes a constraint conflict, there will be no row created.
The auto-increment ID can't be "un-allocated" or otherwise pushed back into a collection of ID values to be handed out. Some other concurrent session might have allocated the next value already, and MySQL does not maintain a pool of ID values, it only knows about the latest value allocated per table.
So MySQL would have to wait until the INSERT had succeeded (including checking all constraints, executing any triggers, etc.), while blocking any other concurrent sessions from doing their INSERTs. Only then could it reliably allocate ID's without "wasting" any values.
That proved to be too constraining on parallelism for MySQL, so their compromise is to quickly allocate an ID, then unlock the auto-increment mechanism for that table, and allow concurrent sessions to proceed. THEN attempt the INSERT using the ID generated. This allows for greater throughput.
Your app prints "Contact Added successfully" even if the INSERT resulted in an error. You don't check for any error in the code you show above, so how do you know it was successful?
Anyway, you shouldn't worry about "wasted" ID values. They are not intended to be consecutive, only unique. If you feel you might run out of integers, then do the math. What is the maximum value of your integer column? What is the rate of generating new values? Based on these, you should be able to figure out how long you've got before you run out. This shouldn't be difficult for a software developer to do this simple math.
The problem was here in this line:
cur = mysql.connect.cursor()
That is inside the function add_contact.
The correct function to use is:
cur = mysql.connection.cursor()
So it was connection instead of connect.
I am using AppEngine with the Python runtime environment to host a dashboard for my team. The data for the dashboard is stored in Memcache and/or Cloud Datastore. New data is pulled into the application using the BigQuery API.
class ExampleForStackOverflow(webapp2.RequestHandler):
def get(self):
credentials = GoogleCredentials.get_application_default()
bigquery_service = build('bigquery', 'v2', credentials=credentials)
query = """SELECT field1, field2
FROM
[table_name];"""
try:
timeout = 10000
num_retries = 5
query_request = bigquery_service.jobs()
query_data = {
'query': (query),
'timeoutMs': timeout,
}
query_response = query_request.query(
projectId='project_name',
body=query_data).execute(num_retries=num_retries)
# Insert query response into datastore
for row in query_response['rows']:
parent_key = ndb.Key(MyModel, 'default')
item = MyModel(parent=parent_key)
item.field1 = row['f'][0]['v']
item.field2 = row['f'][1]['v']
item.put()
except HttpError as err:
print('Error: {}'.format(err.content))
raise err
These queries will return an indeterminate number of records. I want the dashboard to display the results of the queries regardless of the number of records so using order() by created and then using fetch() to pull a certain number of records won't help.
Is it possible to write a query to return everything from the last put() operation?
So far I have tried to return all records that have been written within a certain time window (e.g. How to query all entries from past 6 hours ( datetime) in GQL?)
That isn't working for me in a reliable way because every so often the cron job that queries for the new data will fail so I'm left with a blank graph until the cron job runs the following day.
I need a resilient query that will always return data. Thanks in advance.
You could have an additional DateTimeProperty type property in MyModel, let's call it last_put, which will have the auto_now option set to True. So the datetime of the most recent update of such entity would be captured in its last_put property.
In your get() method you'd start with an ancestor query on the MyModel entities, sorted by last_put and fetching only one item - it will be the most recently updated one.
The last_put property value of that MyModel entity will give the datetime of the last put() you're seeking. Which you can then use in your bigquery query, as mentioned in the post you referenced, to get the entities since that datetime.
Dan's answer led me down the right path but I used a variation of what he suggested (mostly because I don't have a good understanding of ancestor queries). I know this isn't the most efficient way to do this but it'll work for now. Thanks, Dan!
My model:
class MyModel(ndb.Model):
field1 = ndb.StringProperty(indexed=True)
field2 = ndb.StringProperty(indexed=True)
created = ndb.DateTimeProperty(default=datetime.datetime.now())
My query:
query = MyModel.query().order(-MyModel.created)
query = query.fetch(1, projection=[MyModel.created])
for a in query:
time_created = a.created
query = MyModel.query()
query = query.filter(MyModel.created == time_created)
I am pretty sure the code I am doing is logical and makes sense but when I run it against my test the result comes back quite unusual, I am trying find a session from a cookie, and then use it to retrieve the user from the sessions table. I am using the bottle framework to test my program
active_session = bottle.request.get_cookie(COOKIE_NAME)
cursor = db.cursor()
if active_session:
cursor.execute("SELECT usernick FROM sessions WHERE sessionid=?", (active_session, ))
active_user = cursor.fetchone()
return active_user
else:
return None
The result is as follows
self.assertEqual(nick_from_cookie, nick)
AssertionError: ('Bobalooba',) != 'Bobalooba'\
I know I am so close could someone point me in the right direction
if active_session:
cursor.execute("SELECT usernick FROM sessions WHERE sessionid=?", (active_session, ))
active_user = cursor.fetchone()
return active_user[0] if active_user else active_user
It's because you are fetching the entire row and comparing it to a single string. You need to grab the single field contained in the retrieved row. Try this as the input to your assertion.
return active_user[0]
I'm developing a pyramid application and currently in the process of moving from sqlite to postgresql. I've found postgresql more restrictive transaction management is giving me a bad time.
I am using the pyramid_tm because I find it convenient. Most of my problems occur during my async calls. What I have is views that serve up dynamic forms. The idea is - if we got an id that corresponds to a database row we edit the existing row. Otherwise, we are adding a new guy.
#view_config(route_name='contact_person_form',
renderer='../templates/ajax/contact_person_form.pt',
permission='view',
request_method='POST')
def contact_person_form(request):
try:
contact_person_id = request.params['contact_person']
DBSession.begin_nested()
contact_person = DBSession.query(ContactPerson).filter(ContactPerson.id == contact_person_id).one()
transaction.commit()
except (NoResultFound, DataError):
DBSession.rollback()
contact_person = ContactPerson(name='', email='', phone='')
return dict(contact_person=contact_person)
I need to begin a nested transaction because otherwise my lazy request method which is registered with config.add_request_method(get_user, 'user', reify=True) and called when rendering my view
def get_user(request):
userid = unauthenticated_userid(request)
if userid is not None:
user = DBSession.query(Employee).filter(Employee.id == userid).first()
return user
complains that the transaction has been interrupted and the SELECT on employees will be skipped.
I have two questions:
Is it okay to do transaction.commit() on a session.begin_nested() nested transaction? I don't exactly where SQLAlchemy ends and pyramid_tm begins. If I try to commit the session I get an exception that says I can only commit using the transaction manager. On the other hand DBSession.rollback() works fine.
Does handling this like
try:
#do something with db
except:
#oops, let's do something else
make sense? I have the feeling this is 'pythonic', but I'm not sure if this underlying transaction thing calls for non-pythonic means.
Calling transaction.commit() in your code is committing the session and causing your contact_person object to be expired when you try to use it later after the commit. Similarly if your user object is touched on both sides of the commit you'll have problems.
As you said, if there is an exception (NoResultFound) then your session is now invalidated. What you're looking for is a savepoint, which transaction supports, but not directly through begin_nested. Rather, you can use transaction.savepoint() combined with DBSession.flush() to handle errors.
The logic here is that flush executes the SQL on the database, raising any errors and allowing you to rollback the savepoint. After the rollback, the session is recovered and you can go on your merry way. Nothing has been committed yet, leaving that job for pyramid_tm at the end of the request.
try:
sp = transaction.savepoint()
contact_person = DBSession.query(ContactPerson)\
.filter(ContactPerson.id == contact_person_id)\
.one()
DBSession.flush()
except (NoResultFound, DataError):
sp.rollback()
contact_person = ContactPerson(name='', email='', phone='')
return dict(contact_person=contact_person)