I have a time-consuming operation to modify the database which is triggered by request the route,So I want to perform the operation asynchronously without waiting for it to end,and return the state directly. I tried to use threading module in the route,but got this error:
The following is the code:
define a model:
class Plan(db.Model):
__tablename__ = 'opt_version_plans'
planid = db.Column(db.Integer,primary_key=True)
planname = db.Column(db.String(255))
jobname = db.Column(db.String(255))
branch = db.Column(db.String(32))
define function:
def test():
time.sleep(20)
p = Plan.query.get(1)
print p.planname
route:
#app.route('/')
def index():
t = threading.Thread(target=test)
t.start()
return "helloworld"
How can I achieve my needs in this way?
Related
During the running test case of my application, I keep on seeing test failed even when the data is well formatted. The following are my code snippets:
I was able to create a new user through its application interface, but trying its behaviour, it was giving me an unexpected error status code, 422. I don't really know what was going wrong with the snippets. Here I have included all the following code for better look into the stated issue.
For the endpoint /users
#app.route('/users/, methods=['POST'])
def create_user():
try:
body = request.get_json((
new_user = body get('user_name', None)
if user_name is None:
about(405)
new_entry = User(new_user)
new_entry.insert()
return jsonify({
'success': True
)}
except:
abort(422)
Here is my model_class:
class User(db.Model):
__tablename__='users'
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
score = Column(Integer, nullable=False)
def __init__(self, name, score=0):
self.name = name
self.score = score
def insert(self):
db.session.add(self)
db.session.commit()
def format(self):
return {
'id': self.id,
'name': self.name,
'score': self.score
And here is my test_case_file:
class TriviaTestCase(unit test.TestCase):
def setUp(self):
self.app = create_app()
self.client = self.app.test_client
self.database_path = "PostgreSQL://postgres:postgresspass#localhos:5432/user_test_db"
setup_db(self.app, self database_path)
self.new_user = {
"username":"P.Son",
"score": 0
}
def test_create_user(self):
res = self.client().post("/users", json=self.new_user)
data = json.loads(res.data)
self.assertEqual(res.status_code, 200)
self.assertEqual(data['success'], True)
if __name__=="__main__":
unittest.main()
Output of my test:
============================
FAIL: test_create_user (__main__.TriviaTestCase)
----------------------------
Traceback (most recent call last):
File "C:\...\test_flaskr.py", line 201, in test_create_user
self.assertEqual(res.status_code, 200)
AssertionError: 422 != 200
Note Other endpoints pass the test but the above endpoint has been failing test. I don't know what was wrong with the snippets I have written.
First of all, you should always be logging such errors when they happen in your endpoints.
Second, you are returning the 422 error yourself in case of "any" exception and there is some in your code. One of which is the fact that you are just passing user_name to the constructor of the User class but there must be a score variable present too.
Another problem is that you should pass key-value arguments to the User class constructor, not a dictionary.
is should be something like this:
body = request.get_json()
user_name = body.get('user_name', '')
score = body.get('score', '')
if not all([user_name, score]):
# return some customized error here
new_entry = User(user_name=user_name, score=score)
Also, you should consider some form of input validation rather than just checking the data yourself. Something like Marshmellow would be fine.
I have a CRUD football player flask app using SQL Alchemy and postgresql.
I'm trying to test it with unittest and flask-testing but when I test delete and patch request on a player (based on his number), the statut returned is 200 but the player isn't deleted from the database so the test fail.
My app.py :
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='postgresql://postgres:password#localhost:5432/flask-sql-alchemy'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
modus = Modus(app)
class om_player(db.Model):
__tablename__ = "players"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text)
number = db.Column(db.Integer)
age = db.Column(db.Integer)
def __init__(self, name, number, age):
self.name = name
self.number = number
self.age = age
#app.route('/joueurs/<int:number>', methods=["GET", "PATCH", "DELETE"])
def show(number):
found_player = om_player.query.filter_by(number=number).first()
if request.method == b"PATCH":
found_player.name = request.form['name']
found_player.number = request.form['number']
found_player.age = request.form['age']
db.session.add(found_player)
db.session.commit()
return redirect(url_for('show', number=request.form['number']))
if request.method == b"DELETE":
db.session.delete(found_player)
db.session.commit()
return redirect(url_for('joueurs'))
return render_template('show.html', player=found_player)
My test.py:
from app import app,db, om_player
from flask_testing import TestCase
import unittest
class BaseTestCase(TestCase):
def create_app(self):
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:password#localhost:5432/flask-sql-alchemy'
app.config['PRESERVE_CONTEXT_ON_EXCEPTION'] = False
return app
def test_delete(self):
response = self.client.delete('/joueurs/18', follow_redirects=True)
self.assertEqual(response.status_code, 200)
self.assertNotIn(b"AMAVI", response.data)
if __name__ == '__main__':
unittest.main()
(joueurs means players in french)
When I run python test.py :
AssertionError: b'AMAVI' unexpectedly found in b'my edit.html file'
So the player with number 18 and named "AMAVI" is not deleted and I don't understand why since the delete request return 200 and my app is working fine in local server.
If you're using Python3, b"PATCH" and b"DELETE" are no longer doing what you expect. Those tests are failing for "POST" and falling through to the default "GET" case.
Evaluate
"POST" == b"POST"
in a Python3 REPL for confirmation.
I have problems operating with the exiting database in mysql using a sqlalchemy as I need it for building Flask RESTful api.
I get funny errors about circular dependencies here:
from flask import Flask, request, jsonify, make_response
from flaskext.mysql import MySQL
from flask_sqlalchemy import SQLAlchemy
#from webapi import models
# mysql = MySQL()
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secretkey' #for use later
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://user:password#127.0.0.1/mydb'
db = SQLAlchemy(app)
class Extensions(db.Model):
__tablename__ = "Extensions"
extnbr = db.Column(db.Integer, primary_key=True, default="NULL")
authname = db.Column(db.String(256), nullable=True, default="#nobody")
extpriority = db.Column(db.Integer, nullable=True, default=0)
callaccess = db.Column(db.Integer, nullable=True, default=0)
extlocation = db.Column(db.String, nullable=True, default="NULL")
display = db.Column(db.String, nullable=True, default="NULL")
#app.route("/")
def hello():
return "Welcome to Python Flask App!"
#app.route("/extensions", methods=["GET"])
def get_all_extensions():
users = Extensions.query.all()
output = []
for user in users:
user_data = {}
user_data['extnbr'] = user.extnbr
user_data['authname'] = user.authname
user_data['extpriority'] = user.extpriority
user_data['callaccess'] = user.callaccess
user_data['extlocation'] = user.extlocation
user_data['display'] = user.display
output.append({'extensions' : output})
return jsonify({'users' : output})
if __name__ == "__main__":
app.run(debug=True)
I get error about circular dependence:
Debug and trace:
https://dpaste.de/F3uX
This has to do with your output. You're appending a dictionary containing output to output itself, creating a funky data structure causing the json error.
Try changing
output.append({'extensions' : output})
to this:
output.append({'extensions' : user_data })
(Which is what I assume you want anyways)
The problem is:
output = []
for user in users:
...
output.append({'extensions' : output}) # here you are adding output to the output
check this example:
out = []
for i in range(2):
out.append({'ext': out})
# output
[{'ext': [...]}, {'ext': [...]}]
You have the same output. I am sure this is not what you want. So change the line with problem to this one: output.append({'extensions' : user_data})
I'm trying to get a todo_ID using GET method. I'm still new at using sqlalchemy and most of the things i have tried are telling me that sqlalchemy doesn't use them. Also, can someone tell me how to use HEAD, i want my methods to return http statuses, i kinda tried using them and imported the render template but when i try to use them it says it has no idea what they are.
this is my attempt at looking at a tutorial and making changes
from flask import Flask, jsonify,json, request, render_template, abort
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_pyfile('Config.py')
db = SQLAlchemy(app)
class JsonModel(object): # Class for making objects JSON serializable
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
class User(db.Model, JsonModel): # Class which is a model for the User table in the database
User_ID = db.Column(db.Integer, primary_key = True)
FirstName = db.Column(db.String(20))
LastName = db.Column(db.String(20))
def __init__(self,User_ID,FirstName, LastName):
self.User_ID = User_ID
self.FirstName = FirstName
self.LastName = LastName
class Todo(db.Model, JsonModel): # Class which is a model for the Todo table in the database
todo_ID = db.Column(db.Integer, primary_key = True)
UserID = db.Column(db.Integer, db.ForeignKey("user.User_ID"))
details = db.Column(db.String(30))
def __init__(self, UserID, details):
self.UserID = UserID
self.details = details
#app.route('/todo', methods = ['GET']) # Uses GET method to return all information in the database.
def index():
return json.dumps([u.as_dict() for u in User.query.all()+Todo.query.all()]), 201
#app.route('/todo/<int:todo_ID>', methods = ['GET'])
def get(todo_ID):
query = Todo.query.get()
return {'todo': [dict(zip(tuple(query.keys()), i)) for i in query.cursor if i[1] == todo_ID]}
#app.before_first_request #Creates everything before the first request.
def startup():
db.create_all()
if __name__ == '__main__':
app.run()
My most recent attempt was:
#app.route('/todo/<int:todo_ID>', methods = ['GET'])
def get(todo_ID):
query = Todo.query("select * from Todo")
return {'todo': [dict(zip(tuple(query.keys()), i)) for i in query.cursor if i[1] == todo_ID]}
And the error that I get is this.
query = Todo.query("select * from Todo")
TypeError: 'BaseQuery' object is not callable
127.0.0.1 - - [30/Nov/2016 21:15:28] "GET /todo/1 HTTP/1.1" 500 -
If you want to query Todo by primary key and only return one record you can use:
from flask import jsonify
#app.route('/todo/<int:todo_ID>', methods = ['GET'])
def get(todo_ID):
response = {}
todo = Todo.query.get(todo_ID)
response['id'] = todo.id
response['user_id'] = todo.UserID
response['details'] = todo.details
response['status_code'] = 201
return jsonify(response)
Or you can use Marshmallow to have a serializer for each of your models so it can serialize them for you automatically.
Not sure I understand your problem, if your intention is to return json output as response and you want to control the status code, you could
use jsonify
from flask import jsonify
#app.route('/todo/<int:todo_ID>', methods = ['GET'])
def get(todo_ID):
query = Todo.query("select * from Todo")
response = {'todo': [dict(zip(tuple(query.keys()), i)) for i in query.cursor if i[1] == todo_ID]}
response = jsonify(response)
response.status_code = 201
return response
I will dive straight into the code of the application I'm developing using Google App Engine in Python:
import os
import webapp2
import jinja2
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class Users(db.Model):
name = db.StringProperty(required = True)
password = db.StringProperty(required = True)
email = db.EmailProperty(required = True)
address = db.PostalAddressProperty(required = True)
join_date = db.DateTimeProperty(auto_now_add = True)
dob = db.DateTimeProperty()
phone = db.PhoneNumberProperty()
class Orders(db.Model):
name = db.StringProperty(required = True)
email = db.EmailProperty(required = True)
address = db.PostalAddressProperty(required = True)
class MainPage(Handler):
def get(self):
self.render("home.html")
class Register(Handler):
def get(self):
self.render("signup-form.html")
def post(self):
name = self.request.get("username")
password = self.request.get("password")
verify = self.request.get("verify")
email = self.request.get("email")
address = self.request.get("address")
phone = self.request.get("phone")
a = Users(name = name, password = password, email = email, address = address, phone = phone)
a.put()
self.response.write("Registration successful!")
class MP(Handler):
def get(self):
self.render("mp.html")
def post(self):
self.render("order2.html")
class Order2Login(Handler, Register):
def get(self):
self.render("orderlogin.html")
def post(self):
old_usr = self.request.get("loginname")
old_pwd = self.request.get("loginpwd")
ans = a.filter("name =", old_usr).filter("password =", old_pwd)
if ans:
self.response.write("You are a registered member!")
else:
self.response.write("You are NOT registered.")
class Order2New(Handler):
def get(self):
self.response.write("New user yeah")
app = webapp2.WSGIApplication([('/', MainPage),
('/register', Register),
('/mp', MP),
('/order2new', Order2New),
('/order2login', Order2Login)], debug=True)
Now, in the Order2Login class, I needed to access the database object 'a' so that I can confirm whether a user is already a member of my website. Now, for that, I inherited the Register class in my Order2Login class, since the 'a' object was initially created in the Register class.
However, after running my application on my local machine, I get the following error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases Handler, Register
What seems to be the problem in my code?
Inheriting like that doesn't make any sense at all. Even apart from the metaclass problem, inheriting wouldn't make that variable available anyway, since it's a local variable. And in any case, these are two completely separate requests, so data does not persist between them.
But I have no idea why you think you need access to that variable in any case. The User object was persisted to the datastore: in the login view, you don't want to query a, which is a single instance and doesn't have a filter method anyway, you want to query the User class.