Flask-sqlalchemy AttributeError: 'function' object has no attribute 'query' - python

I've been using flask with flask-sqlalchemy successfully for a number of weeks, but all of a sudden my code is coming up with this error: AttributeError: 'function' object has no attribute 'query', relating to this line of code:
project_choices = [(str(c.id) + ': ' + c.project_name) for c in Projects.query.all()]
Seems like the flask-sqalchemy Projects class is not being successfully created but I can't work out why.
Main routes file:
from flask import Flask, request, flash, url_for, redirect, render_template, session
from flask_sqlalchemy import SQLAlchemy
from app import db
from app import app
from app.forms import Basic_data_Form, Which_project#, Areas_form
from flask_bootstrap import Bootstrap
from app.models import Projects
#app.route('/Index', methods = ['GET', 'POST'])
def Index():
if 'project_name' not in session:
session['project_name'] = "0: No project selected"
project_name = session['project_name'].split(':')[1]
project_choices = [(str(c.id) + ': ' + c.project_name) for c in Projects.query.all()]
form2 = Which_project()
form2.project_choice.choices = project_choices
return render_template('Index.html', form2=form2, projects = Projects.query.filter_by(id=session['project_name'].split(':')[0]).all(), project_name=project_name)
init file:
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
bootstrap = Bootstrap(app)
from app import routes
models file:
from app import db
class Projects(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
project_name = db.Column(db.String(100))
user_id = db.Column(db.String(100))
address = db.Column(db.String(100))
region = db.Column(db.String(100))
postcode = db.Column(db.String(20))
building_year = db.Column(db.Integer)
climate_file = db.Column(db.String(100))
building_TFA = db.Column(db.Float)
thermal_mass = db.Column(db.String(100))
winter_int_temp = db.Column(db.Float)
summer_int_temp = db.Column(db.Float)
height_above_sea = db.Column(db.Float)
occupany = db.Column(db.Float)
def __repr__(self):
return '<Project {}>'.format(self.project_name)

I had a similar issue with that same error. It was because there was a function with the same name. So that is probably why it was saying a function had no attribute query even though the table used with sqlalchemy is a class

Consider either implementing a class function which renders the object into the current string representation you desire or implementing a hybrid property.
String method:
class Projects(db.Model):
...
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
project_name = db.Column(db.String(100))
...
def __str__(self):
return f'{self.id}: {self.project_name}'
Use string method as follows:
project_choices = Projects.query.all()
form2 = Which_project()
# probably str(x) would work, but if it doesn't the code below def works
form2.project_choice.choices = [x.__str__() for x in project_choices]
Hybrid property method:
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
class Projects(db.Model):
...
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
project_name = db.Column(db.String(100))
...
#hybrid_property
def project_choice(self):
return f'{self.id}: {self.project_name}'
Use hybrid property as follows:
# Access only the hybrid property
project_choices = Projects.query(Projects.project_choice).all()
form2 = Which_project()
form2.project_choice.choices = project_choices

Related

Python Flask create schedule on startup

I am new-ish to python and new to Flask. I am trying to use APScheduler to schedule a db update when the app starts. It works until I tried to update the database. It says the database is not defined, but I am importing with from .models import Readings. Error can be recreated by uncommenting the lines in interval_task().
init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_apscheduler import APScheduler
from os import path
from flask_login import LoginManager
import pandas as pd
import multiprocessing
import random
db = SQLAlchemy()
DB_NAME_LEOTTA = "leotta.db"
DB_NAME_QUICK = "quick.db"
simulated_room_temperature = multiprocessing.Value('d', 29)
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = '0ddish'
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///databases/{DB_NAME_LEOTTA}'
app.config['SQLALCHEMY_BINDS'] = {'quickdb' : f'sqlite:///databases/{DB_NAME_QUICK}'}
db.init_app(app)
from .views import views
from .auth import auth
from .scheduler import scheduler
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
app.register_blueprint(scheduler, url_prefix='/')
from .models import User, Note, Readings
create_database(app)
sched = APScheduler()
sched.init_app(app)
sched.start()
INTERVAL_TASK_ID = '1'
sched.add_job(id=INTERVAL_TASK_ID, func=interval_task, trigger='interval', seconds=5)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
return app
def create_database(app):
if not path.exists('website/databases/' + DB_NAME_LEOTTA):
#since no bind is specified, it will use default bind
db.create_all(app=app)
print('Created Database ' + DB_NAME_LEOTTA)
if not path.exists('website/databases/' + DB_NAME_QUICK):
db.create_all(bind=DB_NAME_QUICK)
print('Created Database ' + DB_NAME_QUICK)
def interval_task():
simulated_room_temperature.value = random.uniform(19, 31)
#reading = Readings(param_name='Temperature', param_value=simulated_room_temperature.value)
#db.session.add(reading)
#db.session.commit()
print(random.uniform(19, 31))
main.py
from website import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
models.py
from . import db
from flask_login import UserMixin
from sqlalchemy.sql import func
class Note(db.Model):
#no bind specified, will use default
id = db.Column(db.Integer, primary_key=True)
note = db.Column(db.String(150))
date_time = db.Column(db.DateTime(timezone=True), default=func.now('UTC'))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class User(db.Model, UserMixin):
#no bind specified, will use default
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(150), unique=True)
password = db.Column(db.String(150))
first_name = db.Column(db.String(150))
notes = db.relationship('Note')
class Readings(db.Model):
__bind_key__ = 'quickdb'
id = db.Column(db.Integer, primary_key=True)
param_name = db.Column(db.String(150), unique=True)
date_time = db.Column(db.DateTime(timezone=True), default=func.now('UTC'))
param_value = db.Column(db.Float)

SQLAlchemy Marshmallow return empy JSON flask

I'm trying to get a JSON with all registered users, but the request returns an empty object.
Model and Schemas Model
from dataclasses import field
from utils.database import db, ma
from flask_bcrypt import check_password_hash
class Gym(db.Model):
id = db.Column(db.Integer, primary_key=True)
gym_nombre = db.Column(db.String(100))
password = db.Column(db.String(200))
direccion = db.Column(db.String(200))
propietario = db.Column(db.String(200))
telefono = db.Column(db.String(200))
def __init__(self, gym_nombre, password,direccion, propietario,telefono):
self.gym_nombre = gym_nombre
self.password = password
self.direccion = direccion
self.propietario = propietario
self.telefono = telefono
class GymSchemas(ma.Schema):
class meta:
model = Gym
gyms_schemas = GymSchemas(many=True)
gym_schemas = GymSchemas()
Route "usuarios"
from flask import Blueprint, jsonify
from models.model_usuarios import Gym, gyms_schemas
usuarios = Blueprint("usuarios", __name__)
#usuarios.route("/usuarios", methods=['GET'])
def getUsers():
all_users = Gym.query.all()
return jsonify(gyms_schemas.dump(all_users))
Request in postman

Flask-Marshmallow returning empty json and saying my schema is invalid

I am trying to use Marshmallow to serialize my Message Model class yet it is returning an empty json object whenever I try to get the data and after I debugged the program with
print(messagesSchema.validate(messages))
It said: 0: {'_schema': ['Invalid input type.']}
This is my Chat model, Message Model and my MessageSchema model
class Chat(db.Model):
id = db.Column(db.Integer, primary_key=True)
user1 = db.Column(db.String(150), unique=True)
user2 = db.Column(db.String(150), unique=True)
room = db.Column(db.String(300), unique=True)
messages = db.relationship("Message", backref="chat")
class Message(db.Model):
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(300))
username = db.Column(db.String(150))
chat_id = db.Column(db.Integer, db.ForeignKey("chat.id"))
class MessageSchema(ma.SQLAlchemySchema):
class Meta:
model = Message
This is my socketHandler file
messages = Chat.query.filter_by(room=room).first().messages
messagesSchema = MessageSchema(many=True)
print(messagesSchema.validate(messages))
output = messagesSchema.dump(messages)
print(output)
print(jsonify(output))
and the init.py file if anybody is wondering
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from os import path
from flask_login import LoginManager
db = SQLAlchemy()
DB_NAME = "database.db"
ma = Marshmallow()
def create_app():
app = Flask(__name__)
app.config["SECRET_KEY"] = "secret"
app.config["SQLALCHEMY_DATABASE_URI"] = f'sqlite:///{DB_NAME}'
db.init_app(app)
from .views import views
from .auth import auth
from .slashUrl import slashUrl
app.register_blueprint(slashUrl, url_prefix="/")
app.register_blueprint(views, url_prefix="/home/")
app.register_blueprint(auth, url_prefix="/auth/")
from .models import User
create_database(app)
login_manager = LoginManager()
login_manager.login_view = "auth.login"
login_manager.login_message_category = "dangerAlert"
login_manager.init_app(app)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
return app
def create_database(app):
if not path.exists("website/" + DB_NAME):
db.create_all(app=app)
print("Database created")
From my print statements I get
{0: {'_schema': ['Invalid input type.']}}
[{}]
<Response 9 bytes [200 OK]>
If anybody knows how to fix this your help would be greatly appreciated!

<Object id> is not JSON serializable

i'm creating an API in python + Flask + marshmallow.
Here's the class + the first function (i don't already use the others )
import datetime
from marshmallow import Schema, fields, ValidationError, pre_load
from flask import Flask, jsonify
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from flask import request
import os
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'User.sqlite')
# Order matters: Initialize SQLAlchemy before Marshmallow
db = SQLAlchemy(app)
ma = Marshmallow(app)
class User(db.Model):
userid = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
badgenum = db.Column(db.String(30))
mail = db.Column(db.String(30))
status = db.Column(db.String(30))
admin = db.Column(db.String(30))
def __init__(self, userid, name, badgenum, mail, status, admin):
self.userid = userid
self.name = name
self.badgenum = badgenum
self.mail = mail
self.status = status
self.admin = admin
class UserSchema(ma.Schema):
class Meta:
fields = ('userid', 'name', 'badgenum', 'mail', 'status', 'admin')
user_schema = UserSchema()
users_schema = UserSchema(many=True)
#app.route("/User", methods=["POST"])
def add_User():
userid = request.json['userid']
name = request.json['name']
badgenum = request.json['badgenum']
mail = request.json['mail']
status = request.json['status']
admin = request.json['admin']
new_user = User(userid, name, badgenum, mail, status, admin)
db.session.add(new_user)
db.session.commit()
return jsonify(new_user)
I tested the function add_User using Postman with this json request :
{
"userid" : 1,
"name" : "name1",
"badgenum" : "66897",
"mail" : "ghh#orange.fr",
"status" : "on",
"admin" : "f"
}
and i got this error:
TypeError: <User 145> is not JSON serializable
User has its own autogenerated id user.id which is ObjectId.
You need custom json encoder to encode ObjectId field.
import json, bson
def json_response(obj, cls=None):
response = make_response(json.dumps(obj, cls=cls))
response.content_type = 'application/json'
return response
class MongoJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, bson.ObjectId):
return str(obj)
return json.JSONEncoder.default(self, obj)
Now try to call return json_response(new_user, cls=MongoJsonEncoder)

Eve Authentication with bcrypt driver.db error when sending curl request

I use bcrypt for the authentication of my resources and have accounts stored in mydatabase with username and passwords. I have stored the passwords manually as hashes in the database as follows:
I started the python bash and typed in following code:
import bcrypt
password = u'passwordtobehashed'
password_hashed = bcrypt.hashpw(password, bcrypt.gensalt())
print (password_hashed)
Then i copied the output of print and stored it in the account table via a POST Request(w/o authentication):
curl -d '{"username": "someuser", "password": "somehashedpassword", "roles_id": 1}' -H 'Content-Type: application/json' http://127.0.0.1:5000/account
Well I use SQLAlchemy and eve is also up to date (Version: 0.7.1).
Well I request for example the people resource using Bcrypted Authentication as follows:
curl -u username 127.0.0.1:5000/people
Then I enter my password and I get following error:
File "/home/vagrant/erpghost/restapi/oldtrivial.py", line 57, in check_auth
accounts = app.data.driver.db['account']
AttributeError: 'SQLAlchemy' object has no attribute 'db'
For some reason the db attribute is not available. I also tried to use Eve.app.data.driver.db and I tried importing current_app from flask but that all did not work.
Well here is my code:
oldtrivial.py
from eve.auth import BasicAuth
from eve import Eve
from eve_sqlalchemy import SQL
from eve_sqlalchemy.validation import ValidatorSQL
import bcrypt
from connection import connect
from connection import Base
con, meta = connect()
Base.metadata.create_all(con)
class BCryptAuth(BasicAuth):
def check_auth(self, username, password, allowed_roles, resource, method):
accounts = app.data.driver.db['account']
account = accounts.find_one({'username': username})
return account and \
bcrypt.hashpw(password, account['password']) == account['password']
app = Eve(validator=ValidatorSQL, data=SQL, auth=BCryptAuth)
db = app.data.driver
Base.metadata.bind = db.engine
db.Model = Base
db.create_all()
if __name__ == '__main__':
app.run(debug=True, use_reloader=False)
tables.py
from sqlalchemy.orm import column_property
from sqlalchemy import Column, Integer, String, DateTime, func, ForeignKey
from connection import connect
from eve.auth import BasicAuth
from connection import Base
from sqlalchemy.orm import relationship
con, meta = connect()
class CommonColumns(Base):
__abstract__ = True
_created = Column(DateTime, default=func.now())
_updated = Column(DateTime, default=func.now(), onupdate=func.now())
_etag = Column(String(40))
class People(CommonColumns):
__tablename__ = 'people'
_id = Column(Integer, primary_key=True, autoincrement=True)
firstname = Column(String(80))
lastname = Column(String(120))
fullname = column_property(firstname + " " + lastname)
class Roles(CommonColumns):
__tablename__ = 'roles'
_id = Column(Integer, primary_key=True, autoincrement=True)
role = Column(String(80))
class Account(CommonColumns):
__tablename__ = 'account'
_id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50), nullable=False, unique=True)
password = Column(String(200), nullable=False)
roles = relationship("Roles", backref="account")
roles_id = Column(Integer, ForeignKey('roles._id'))
settings.py
from eve_sqlalchemy.decorators import registerSchema
from eve.utils import config
from tables import People
from tables import Account
from tables import Roles
registerSchema('people')(People)
registerSchema('roles')(Roles)
registerSchema('account')(Account)
DOMAIN = {
'people': People._eve_schema['people'],
'roles': Roles._eve_schema['roles'],
'account': Account._eve_schema['account'],
}
DOMAIN['account'].update({
'additional_lookup': {
'url': 'regex("[\w]+")',
'field': 'username'
},
'cache_control': '',
'cache_expires': 0,
'allowed_roles': ['superuser', 'admin'],
'authentication': None,
})
SQLALCHEMY_DATABASE_URI = 'postgresql://databaseuser:password#localhost:5432/database'
RESOURCE_METHODS = ['GET', 'POST']
ITEM_METHODS = ['GET', 'DELETE', 'PATCH', 'PUT']
DEBUG = True
config.ID_FIELD = config.ITEM_LOOKUP_FIELD = '_id'
DOMAIN['people']['id_field'] = config.ID_FIELD
DOMAIN['roles']['id_field'] = config.ID_FIELD
DOMAIN['account']['id_field'] = config.ID_FIELD
Hope someone can help me out.
Something along these lines should work:
from flask import current_app
from tables import Account
# ...
def check_auth(...):
session = current_app.data.driver.session
return session.query(Account) \
.filter(Account.username == username,
Account.password == hashed_password) \
.count() > 0
I guess you've tried to mimic the code in http://python-eve.org/authentication.html#basic-authentication-with-bcrypt ? This is for using Mongo-DB instead of SQLAlchemy.

Categories

Resources