I'm completely new to flask and web development in general. And what I need is to login to a website using steam id. I'm doing it as it said here, but get the following error:
OperationalError: (sqlite3.OperationalError) no such table: user
It seems to open up steam website correctly but it breaks when I press Log In. So, what's my mistake ? Any help is appreciated.
The code:
from flask import Flask, render_template, redirect, session, json, g
from flask_bootstrap import Bootstrap
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.openid import OpenID
import urllib
import re
app = Flask(__name__)
app.secret_key = '123'
Bootstrap(app)
app.config.from_pyfile('settings.cfg')
db = SQLAlchemy(app)
oid = OpenID(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
steam_id = db.Column(db.String(40))
nickname = db.String(80)
#staticmethod
def get_or_create(steam_id):
rv = User.query.filter_by(steam_id=steam_id).first()
if rv is None:
rv = User()
rv.steam_id = steam_id
db.session.add(rv)
return rv
def get_steam_userinfo(steam_id):
options = {
'key': app.config['STEAM_API_KEY'],
'steamids': steam_id
}
url = 'http://api.steampowered.com/ISteamUser/' \
'GetPlayerSummaries/v0001/?%s' % urllib.urlencode(options)
rv = json.load(urllib.urlopen(url))
return rv['response']['players']['player'][0] or {}
_steam_id_re = re.compile('steamcommunity.com/openid/id/(.*?)$')
#app.route('/login')
#oid.loginhandler
def login():
if g.user is not None:
return redirect(oid.get_next_url())
return oid.try_login('http://steamcommunity.com/openid')
#oid.after_login
def create_or_login(resp):
match = _steam_id_re.search(resp.identity_url)
g.user = User.get_or_create(match.group(1))
steamdata = get_steam_userinfo(g.user.steam_id)
g.user.nickname = steamdata['personaname']
db.session.commit()
session['user_id'] = g.user.id
flash('You are logged in as %s' % g.user.nickname)
return redirect(oid.get_next_url())
#app.before_request
def before_request():
g.user = None
if 'user_id' in session:
g.user = User.query.get(session['user_id'])
#app.route('/')
def homepage():
return render_template('mainpage.html')
#app.route('/logout')
def logout():
session.pop('user_id', None)
return redirect(oid.get_next_url())
if __name__ == '__main__':
app.run(debug=True)
You need to run a db.create_all() before running your app.
This will create all the tables described by your model in the database.
If you are new to flask you can follow the quickstart quide here
Related
I'm trying to post and get objects using Flask but I keep getting sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: object.
I tried doing POST into http://127.0.0.1/data
and the json I provided is
{
"oid": "123456789",
"size": "1234"
}
Below is my code
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'
db = SQLAlchemy(app)
class Object(db.Model):
oid = db.Column(db.Integer, primary_key=True)
size = db.Column(db.Integer)
def __repr__(self):
return f'Object: {self.oid}, Size: {self.size}'
#app.route('/')
def index():
return 'DSAP_2022'
#app.route('/data/<oid>', methods=['GET'])
def getObject(oid):
obj = Object.query.filter_by(oid=oid).first()
if obj is None:
return 'Object not found', 404
return repr(obj)
#app.route('/data', methods=['POST'])
def putObject():
obj = Object(oid=request.json['oid'], size=request.json['size'])
db.session.add(obj)
db.session.commit()
return 'OK'
if __name__ == '__main__':
app.run()
I am using Postman to submit my requests. and the index() works, however, both getObject and putObject doest not work because of the same error.
You're never calling db.create_all() to create the database tables. You would need something like:
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'
db = SQLAlchemy(app)
class Object(db.Model):
oid = db.Column(db.Integer, primary_key=True)
size = db.Column(db.Integer)
def __repr__(self):
return f'Object: {self.oid}, Size: {self.size}'
# Create tables corresponding to sqlalchemy models
db.create_all()
#app.route('/')
def index():
return 'DSAP_2022'
#app.route('/data/<oid>', methods=['GET'])
def getObject(oid):
obj = Object.query.filter_by(oid=oid).first()
if obj is None:
return 'Object not found', 404
return repr(obj)
#app.route('/data', methods=['POST'])
def putObject():
obj = Object(oid=request.json['oid'], size=request.json['size'])
db.session.add(obj)
db.session.commit()
return 'OK'
if __name__ == '__main__':
app.run()
I have the following app.py:
from flask import Flask
from waitress import serve
from bprint import api_blueprint
from errors import invalid_id, not_found, invalid_input, internal_server_error, unauthorized_access
app = Flask(__name__)
app.register_blueprint(api_blueprint)
app.register_error_handler(400, invalid_id)
app.register_error_handler(401, unauthorized_access)
app.register_error_handler(404, not_found)
app.register_error_handler(405, invalid_input)
app.register_error_handler(500, internal_server_error)
if __name__ == "__main__":
serve(app, host='localhost')
And the following code in bprint.py:
from flask import Blueprint, jsonify, request
import dbu
from models import Session, user_table, car_table, order_table
from schema import UserDetails, UserQuery, OrderDetails, OrderQuery, CarDetails, CarQuery, LoginData, \
ListUsersReq, Response
from contextlib import contextmanager
from flask_jwt_extended import jwt_required, create_access_token, get_jwt_identity
import datetime
api_blueprint = Blueprint('api', __name__)
#contextmanager
def session_scope():
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
else:
try:
session.commit()
except:
session.rollback()
raise
#api_blueprint.route("/login", methods=["POST"])
def login():
from app import bcrypt
data = LoginData().load(request.json)
if data:
user = dbu.get_entry_by_username(user_table, username=data["username"])
hpw = bcrypt.generate_password_hash(data["password"])
if not user:
return jsonify({"message": "Couldn't find user!"})
if bcrypt.check_password_hash(hpw, data["password"]):
access_token = create_access_token(identity=data["username"], expires_delta=datetime.timedelta(days=365))
return jsonify(access_token=access_token, id=user.id), 200
#api_blueprint.route("/user", methods=["GET"])
def list_users():
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin:
args = ListUsersReq().load(request.args)
userlist = dbu.list_users(args.get("email"), args.get("username"))
return jsonify(UserDetails(many=True).dump(userlist))
else:
return jsonify(code=401, type='UNAUTHORIZED_ACCESS'), 401
#api_blueprint.route("/user", methods=["POST"])
def create_user():
with session_scope():
from app import bcrypt
user_details = UserQuery().load(request.get_json(force=True))
user_details["password"] = bcrypt.generate_password_hash(user_details["password"]).decode('UTF-8')
user = dbu.create_entry(user_table, **user_details)
access_token = create_access_token(identity=user.username, expires_delta=datetime.timedelta(days=365))
return jsonify(access_token=access_token, id=UserDetails().dump(user)["id"]), 200
#api_blueprint.route("/user/<int:id>", methods=["GET"])
def user_by_id(id):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin:
user = dbu.get_entry_by_id(user_table, id)
return jsonify(UserDetails().dump(user))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/user/<int:id>", methods=["PUT"])
def update_user(id):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin or user.id == id:
user_details = UserQuery().load(request.json)
user = dbu.get_entry_by_id(user_table, id)
dbu.update_entry(user, **user_details)
return jsonify(Response().dump({"code": "200"}))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/user/<int:id>", methods=["DELETE"])
def delete_user(id):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin or user.id == id:
dbu.delete_entry(user_table, id)
return jsonify(Response().dump({"code": "200"}))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/cars", methods=["GET"])
def get_inventory():
with session_scope():
cars = dbu.list_cars()
return jsonify(CarDetails(many=True).dump(cars))
#api_blueprint.route("/cars/car/<int:carId>", methods=["GET"])
def get_car_by_id(carId):
with session_scope():
car = dbu.get_car_by_id(car_table, carId)
return jsonify(CarDetails().dump(car))
#api_blueprint.route("/cars/car", methods=["POST"])
def create_car():
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin:
car_details = CarQuery().load(request.json)
car = dbu.create_entry(car_table, **car_details)
return jsonify({"carId": CarDetails().dump(car)["carId"]})
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/cars/car/<int:carId>", methods=["PUT"])
def update_car(carId):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin:
car_details = CarQuery().load(request.json)
car = dbu.get_car_by_id(car_table, carId)
dbu.update_entry(car, **car_details)
return jsonify(Response().dump({"code": "200"}))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/cars/car/<int:carId>", methods=["DELETE"])
def delete_car(carId):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin:
dbu.delete_car(car_table, carId)
return jsonify(Response().dump({"code": "200"}))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/cars/car/<int:carId>/order", methods=["POST"])
def place_order(carId):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user:
order_data = OrderQuery().load(request.json)
order = dbu.create_entry(order_table,
userId=user.id,
carId=carId,
shipDate=order_data["shipDate"],
returnDate=order_data["returnDate"],
status="placed",
complete=False)
return jsonify({"id": OrderDetails().dump(order)["id"]})
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/orders", methods=["GET"])
def get_orders():
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user.admin:
orders = dbu.list_orders()
return jsonify(OrderDetails(many=True).dump(orders))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/cars/car/<int:carId>/order/<int:orderId>", methods=["GET"])
def get_order_by_id(carId, orderId):
with session_scope():
current_user = get_jwt_identity()
user = dbu.get_entry_by_username(user_table, current_user)
if user:
order = dbu.get_entry_by_id(order_table, id=orderId)
return jsonify(OrderDetails().dump(order))
else:
return jsonify(code=401, type="UNAUTHORIZED_ACCESS"), 401
#api_blueprint.route("/cars/car/<int:carId>/order/<int:orderId>", methods=["DELETE"])
def delete_order(carId, orderId):
with session_scope():
dbu.delete_entry(order_table, id=orderId)
return jsonify(Response().dump({"code": "200"}))
When I try to run waitress-serve --port=5000 app:app I get the following error:
app.register_blueprint(api_blueprint)
raise AssertionError(
AssertionError: View function mapping is overwriting an existing endpoint function: api.wrapper
What may be the problem?
I'm almost sure it worked in December and now after reinstalling my Windows it doesn't
Now it also says I have too much code in my question and I don't know how to explain my problem with more words, so I have to add a few useless lines, sorry
Check if you have some custom decorators on views. Because flask take endpoint name either from #route parameter or from function name. In your case there're no endpoint parameter in any of functions.
Error says api.wrapper and it means that you have 2 or more function with name wrapper. Usually we see such name inside decorators. So you probably have decorator that looks like
def decorator(f):
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
return wrapper
And some views are decorated with such decorator. And flask take "wrapper" as a view name
Try by commenting few lines of code - It may help you to resolve your issue.
from flask import Flask
from waitress import serve
from bprint import api_blueprint
# from errors import invalid_id, not_found, invalid_input, internal_server_error, unauthorized_access
app = Flask(__name__)
app.register_blueprint(api_blueprint)
# app.register_error_handler(400, invalid_id)
# app.register_error_handler(401, unauthorized_access)
# app.register_error_handler(404, not_found)
# app.register_error_handler(405, invalid_input)
# app.register_error_handler(500, internal_server_error)
if __name__ == "__main__":
serve(app, host='localhost')
When i try run the app the first db works proprtly but the second one does not and return error 405 could anyone post solution for multiple databes
enter image description here
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///storage.db'
db = SQLAlchemy(app)
dbTodo = SQLAlchemy(app)
class Todo(dbTodo.Model): #<=LIKE THIS
id = dbTodo.Column(db.Integer,primary_key=True)
content = dbTodo.Column(db.String(200),nullable=False)
blockId = dbTodo.Column(db.Integer)
class Blocks(db.Model): #<=LIKE THIS
id = db.Column(db.Integer,primary_key=True);
date_create = db.Column(db.DateTime,default=datetime.utcnow)
#app.route('/addto/<int:id>',methods=['POST'])
def addto(id):
if request.method == 'POST':
todo = Todo(content=request.form['content'],blockId=id)
dbTodo.session.add(todo)
dbTodo.session.commit()
print(Blocks.query.order_by(Blocks.date_create).all())
return redirect('/')
else:
print(Blocks.query.order_by(Blocks.date_create).all())
return "failed"
if __name__ == "__main__":
app.run(debug=True)
what you are looking for are binds. Have a look in the docs:
https://flask-sqlalchemy.palletsprojects.com/en/2.x/binds/
SQLALCHEMY_DATABASE_URI = 'postgres://localhost/main'
SQLALCHEMY_BINDS = {
'users': 'mysqldb://localhost/users',
'appmeta': 'sqlite:////path/to/appmeta.db'
}
db.create_all()
db.create_all(bind=['users'])
db.create_all(bind='appmeta')
db.drop_all(bind=None)
I creating my first bot using Flask, Twilio, Dialogflow to be deployed at Heroku. My local development is using SQLite but final version should use POSTGRES.
Yesterday as I began to store data to local db, I started getting this error as I try to identify the user that is sending message.
The idea is that, after user is created at db, I will store every message that he sent and every response given by dialogflow. But even though the user is being created at my db, I'm failing to query for his user_id afterwards.
Since it's not an actual error, but not finding the user, I'm posting the code below and printing some parts of it that I'm being trying to use to debug.
CODE:
import os
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from twilio.twiml.messaging_response import MessagingResponse
from sportsbot.utils import fetch_reply
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///myDB.db' #path to database and its name
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #supress warning of changes on database
db = SQLAlchemy(app)
#app.debug = True
from sportsbot.models import User, Team, Matches, Messages
#app.route('/')
def hello():
return "hello world!"
#app.route('/whatsapp', methods=['POST'])
def sms_reply():
"Check if user is new, create user at db if it is"
phone_no = int(request.form.get('From').split(':')[1][1:])
if User.query.filter(User.user_phone_no == phone_no).count() == 0:
user = User(user_phone_no=phone_no)
db.session.add(user)
db.session.commit()
print("New user")
else:
print("User already at base")
#tring to debug
print(phone_no)
user_id = User.query.filter(User.user_phone_no == phone_no).first()
print(user_id)
msg = request.form.get('Body')
reply = fetch_reply(msg,phone_no)
"Reply to it"
print(reply['text'])
print(reply['intent'])
resp = MessagingResponse()
resp.message(reply['text'])
#message = Messages(user_id = user_id, message= msg, response=reply['text'],intent=reply['intent'])
#db.session.add(message)
#try:
# db.session.commit()
#except:
# db.session.rollback()
return str(resp)
if __name__ == "__main__":
app.run(debug=True)
User class:
class User(db.Model):
user_id = db.Column(db.Integer, primary_key=True)
user_name = db.Column(db.String(80), index = True, unique = False)
user_phone_no = db.Column(db.Integer, index = True, unique = True)
team_id = db.Column(db.Integer, db.ForeignKey('team.team_id'))
def __repr__(self):
return "{}".format(self.user_name)
Prints:
User already at base
5511990046548
None
Oi! Bem Vindo ao EsporteBot. VocĂȘ gostaria de saber sobre algum time ou quer a agenda de eventos da semana?
Default Welcome Intent
Any idea of what I'm doing wrong since it sees the user at db but cannot find it afterwards?
This code
User.query.filter(User.user_phone_no == phone_no).count()
finds 1 user
This code
user_id = User.query.filter(User.user_phone_no == phone_no).first()
gives None as answer
Code works correctly.
Problem is that in model User you created own __repr__() which displays user_name but you don't add user_name to database so it uses None as user_name and when you run first() then this __repr__() prints None as user_name - and this is why you get None on screen.
When you use
def __repr__(self):
return "name: {}".format(self.user_name)
then you get name: None instead of None
Maybe better use
def __repr__(self):
return "id: {}, name: {}, phone no: {}".format(self.user_id, self.user_name, self.user_phone_no)
to get more information.
Or simply remove __repr__ from your model and then you will see something like <User 1>
Minimal working example which everyone can execute:
import os
from flask import Flask, request, render_template_string
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///myDB.db' #path to database and its name
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False #supress warning of changes on database
db = SQLAlchemy(app)
db.create_all()
class User(db.Model):
user_id = db.Column(db.Integer, primary_key=True)
user_name = db.Column(db.String(80), index = True, unique = False)
user_phone_no = db.Column(db.Integer, index = True, unique = True)
def __repr__(self):
#return "{}".format(self.user_name)
#return "name: {}".format(self.user_name)
return "id: {}, name: {}, phone no: {}".format(self.user_id, self.user_name, self.user_phone_no)
#db.create_all()
#app.route('/')
def hello():
return render_template_string("""
<form method="POST" action="/whatsapp">
Phone <input name="From" value="James Bond:+007"></input>
<button type="submit">OK</button>
</form>
""")
#app.route('/whatsapp', methods=['POST'])
def sms_reply():
"Check if user is new, create user at db if it is"
parts = request.form.get('From').split(':')
user_name = parts[0]
phone_no = int(parts[1][1:])
if User.query.filter(User.user_phone_no == phone_no).count() == 0:
#user = User(user_phone_no=phone_no)
user = User(user_phone_no=phone_no, user_name=user_name)
db.session.add(user)
db.session.commit()
print("New user")
else:
print("User already at base")
#tring to debug
print('phone_no:', phone_no)
user = User.query.filter(User.user_phone_no == phone_no).first()
print('user:', user)
return render_template_string("""{{user}}""", user=user)
if __name__ == "__main__":
app.run(debug=True)
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