Flask-SQLAlchemy - Order shows by number of followers - python

I am trying to create a query which will return all shows in database ordered by number of users who have it as favorite.
Simplified working code:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
import logging
app = Flask(__name__)
db = SQLAlchemy(app)
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
favorite_series = db.Table('favorite_series',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('series_id', db.Integer, db.ForeignKey('series.id')))
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
favorite_series = db.relationship('Serie', secondary=favorite_series,
backref=db.backref('users', lazy='dynamic'))
def __repr__(self):
return '<User {0}>'.format(self.name)
class Serie(db.Model):
__tablename__ = 'series'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
def __repr__(self):
return '<Serie {0}>'.format(self.name)
u1 = User()
u1.name = 'user1'
u2 = User()
u2.name = 'user2'
u3 = User()
u3.name = 'user3'
s1 = Serie()
s1.name = 'Serie1'
s2 = Serie()
s2.name = 'Serie2'
s3 = Serie()
s3.name = 'Serie3'
s4 = Serie()
s4.name = 'Serie4'
s5 = Serie()
s5.name = 'Serie5'
u1.favorite_series.extend([s1, s3, s5])
u2.favorite_series.extend([s1, ])
u3.favorite_series.extend([s1, s2, s3])
u1.favorite_series.extend([s1, s2])
db.session.add(u1)
db.session.add(u2)
db.session.add(u3)
db.session.add(s1)
db.session.add(s2)
db.session.add(s3)
db.session.add(s4)
db.session.add(s5)
db.create_all()
db.session.commit()
And I try to retrieve them with:
shows = Serie.query.join(Serie.users).order_by(func.count(Serie.users)).all()
print shows
But this throws error in SQL syntax, I tried to search for something but could not come up with anything working.
Any help would be appreciated.

Working solution:
sub = db.session.query(favorite_series.c.series_id, func.count(favorite_series.c.user_id).label('count')).group_by(favorite_series.cā€Œā€‹.series_id).subquery()
shows = db.session.query(Serie, sub.c.count).outerjoin(sub, Serie.id == sub.c.series_id).order_by(db.desc('count')).all()

Related

Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS

I am trying to create an API in Python that uses a Postgresql database. I am attempting a simple endpoint to pull to check to see if the database can connect and pull data. I am probably missing something simple and need someone to point it out. Below is my main.py file
import psycopg2
import model
import os
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
uname = os.environ['uname']
pas = os.environ['pas']
url = os.environ['url']
port = os.environ['port']
dbase = os.environ['dbase']
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://' + uname + ':' + pas + '#' + url + ':' + port + '/' + dbase
db = SQLAlchemy(app)
#app.route('/test')
def test():
tst = model.Doc.query.filter_by(doc_num=1).first()
return jsonify(tst)
if __name__ == '__main__':
app.run()
I also have a model.py file where my database is modeled out.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Date, ForeignKey
from flask_marshmallow import Marshmallow
app = Flask(__name__)
db = SQLAlchemy(app)
ma = Marshmallow(app)
class Aud(db.Model):
__tablename__ = 'aud'
__table_args__ = {'schema': 'cirsx'}
aud_num = Column(Integer, primary_key=True)
aud_name = Column(String, nullable=False, unique=True)
aud_desc = Column(String)
class AudSchema(ma.Schema):
class Meta:
fields = ('aud_num', 'aud_name', 'aud_desc')
class DocTyp(db.Model):
__tablename__ = 'doctyp'
__table_args__ = {'schema': 'cirsx'}
doctyp_num = Column(Integer, primary_key=True)
doctyp_name = Column(String, nullable=False, unique=True)
doctyp_desc = Column(String)
class DocTypSchema(ma.Schema):
class Meta:
fields = ('doctyp_num', 'doctyp_name', 'doctyp_desc')
class Doc(db.Model):
__tablename__ = 'doc'
__table_args__ = {'schema': 'cirsx'}
doc_num = Column(Integer, primary_key=True)
doctyp_num = Column(Integer, ForeignKey('doctyp_num'))
aud_num = Column(Integer, ForeignKey('aud_num'))
doc_path = Column(String, nullable=False)
title = Column(String, nullable=False)
author = Column(String)
keywords = Column(String)
pub_dt = Column(Date)
doc_abs = Column(String)
doc_txt = Column(String)
class DocSchema(ma.Schema):
class Meta:
fields = ('doc_num',
'doctyp_num',
'aud_num',
'doc_path',
'title',
'author',
'keywords',
'pub_dt',
'doc_abs',
'doc_txt')
aud_schema = AudSchema()
aud_schemas = AudSchema(many=True)
doctyp_schema = DocTypSchema()
doctyp_schemas = DocTypSchema(many=True)
doc_schema = DocSchema()
doc_schemas = DocSchema(many=True)
if __name__ == '__main__':
app.run()
Is there something that I am missing to why I am getting this error?

missing user_loader error exception in flask app

I am trying to create a basic blog post website. Everything was going fine until i tried to run the app and it showed me the error:-
"Exception: Missing user_loader or request_loader"
but I have already created the user_loader. so I tried to find solutions and in the process I found that flask db migrate is not creating any table. so I searched online and found a solution to add all my tables in evn.py file in migration folder. I thought that was the problem and I tried to run the app again and this appeared again:-
"Exception: Missing user_loader or request_loader"
This is my __init__py file
# blogpost/__init__.py
import os
import secrets
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(8)
# DATABASE CONFIGURATION #############
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
# LOGIN CONFIGURATION #################
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
# IMPORTING BLUEPRINTS #################################
from blogpost.core.views import core
from blogpost.user.views import users
# BLUEPRINTS CONFIGURATION #################################
app.register_blueprint(core)
app.register_blueprint(users)
and this is my models.py file.
from blogpost import db, login_manager
from flask_login import UserMixin
from datetime import datetime
from werkzeug.security import check_password_hash, generate_password_hash
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
fav_posts = db.Table('fav_posts',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('fav_posts_id', db.Integer, db.ForeignKey('posts.id')))
follows = db.Table('follows',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('follows', db.Integer, db.ForeignKey('users.id')))
fav_tags = db.Table('fav_tags',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('fav_tags_id', db.Integer, db.ForeignKey('tags.id')))
licked_posts = db.Table('licked_posts',
db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
db.Column('user_id', db.Integer, db.ForeignKey('users.id')))
tags_included = db.Table('tags_included',
db.Column('post_id', db.Integer, db.ForeignKey('posts.id')),
db.Column('user_id', db.Integer, db.ForeignKey('tags.id')))
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
email = db.Column(db.String, unique=True, index=True)
dob = db.Column(db.Date)
password_hash = db.Column(db.String)
account_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
profile_image = db.Column(db.String)
is_verified = db.Column(db.Boolean, default=False)
posts = db.relationship('Post', backref='author', lazy=True)
favorite_posts = db.relationship('Post', secondary=fav_posts, backref=db.backref('fav_by', lazy='dynamic'))
followers = db.relationship('User', secondary=follows, backref=db.backref('following', lazy='dynamic'))
favorite_tags = db.relationship('Tag', secondary=fav_tags, backref=db.backref('users', lazy='dynamic'))
def __init__(self, email, password, username, dob):
self.email = email
self.username = username
self.dob = dob
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String)
body = db.Column(db.Text)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
likes = db.relationship('User', secondary=licked_posts, backref=db.backref('licked_by', lazy='dynamic'))
tags_includes = db.relationship('Tag', secondary=tags_included,
backref=db.backref('post_including_tag', lazy='dynamic'))
def __init__(self, title, body):
self.title = title
self.body = body
class Tag(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
def __init__(self, name):
self.name = name
can anyone one tell me what should I do to solve this and more importantly what is the cause because I have done same in my previous project but this never happened.
UPDATE:-
I've solved this problem by creating my user_loader inside my init file after the login_manager.login_view = 'users.login' file. I imported the User model after this line and then created the user_loader.
so my guess is that the problem is that flask is not able to find the "models.py" file. if anyone can explain the problem accurately or have a better solution you're most welcome (^-^)
here is another work i did for practice and it worked fine.
#puppycompanyblog/__init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
#DATABASE SETUP##########################
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir,'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATION'] = False
db = SQLAlchemy(app)
Migrate(app,db)
#########################################
#LOGIN CONFIGURATIONS####################
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'users.login'
#########################################
from puppycompanyblog.core.views import core
from puppycompanyblog.users.views import users
from puppycompanyblog.blog_posts.views import blog_posts
from puppycompanyblog.error_pages.handlers import error_pages
app.register_blueprint(core)
app.register_blueprint(users)
app.register_blueprint(blog_posts)
app.register_blueprint(error_pages)
and
# puppycompanyblog/models.py
from puppycompanyblog import db, login_manager
from werkzeug.security import check_password_hash, generate_password_hash
from flask_login import UserMixin
from datetime import datetime
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
profile_image = db.Column(db.String(64), nullable=False, default='default_profile.png')
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('BlogPost', backref='author', lazy=True)
def __init__(self, email, username, password, ):
self.email = email
self.username = username
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def __repr__(self):
return f"username: {self.username}"
class BlogPost(db.Model):
users = db.relationship(User)
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
title = db.Column(db.String(140), nullable=False)
text = db.Column(db.Text, nullable=False)
def __init__(self, title, text, user_id):
self.title = title
self.text = text
self.user_id = user_id
def __repr__(self):
return f"Post ID: {self.id} -- Date: {self.date} --- {self.title}"
The reason why the user_loader function isn't found is because you are not importing the module in which it is defined. You put it in models.py, so you need to import this module somewhere in the area where you define your application, so that the handler is registered with the Flask-Login extension. You'll also need to import this file so that Flask-SQLAlchemy registers your models.
Based on the code that you posted, you could add import models at the bottom of blogpost/__init__.py and I think that should do it (it needs to be at the bottom to prevent circular imports).

Get list of all relationships from a table Flask SQLalchemy

I'm trying to get a list of all the relationships for a table with Flask SQLAlchemy, but don't see any option, just on how to create relationships.
Does anyone know how I can do this? Any help is much appreciated.
Here is a simple example of 3 models. How can I get a list of the two relationships from the Member model?
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
import os
from flask_login import UserMixin
app = Flask(__name__)
file_path = os.path.abspath(os.getcwd()) + "\database.db"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + file_path
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] = "my secret!"
db = SQLAlchemy(app)
class Member(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String(40), unique = True)
hobbies = db.relationship("Hobbies", backref="member", lazy="dynamic")
friends = db.relationship("Friends", backref="member", lazy="dynamic")
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Member {}>".format(self.id)
class Hobbies(db.Model):
id = db.Column(db.Integer, primary_key = True)
hobby = db.Column(db.String(40))
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
def __init__(self, hobby, user_id):
self.hobby = hobby
self.user_id = user_id
def __repr__(self):
return "<Hobbies {}>".format(self.id)
class Friends(db.Model):
id = db.Column(db.Integer, primary_key = True)
friend = db.Column(db.String(40))
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
def __init__(self, friend, user_id):
self.friend = friend
self.user_id = user_id
def __repr__(self):
return "<Friends {}>".format(self.id)
from sqlalchemy.inspection import inspect
relations = inspect(Member).relationships.items()

Flask-SQLAlchemy not creating my tables

SQLAlchemy and for some reason when i run my create_db.py only the migration table is created.
I tried it from python terminal with from modules import db,models then running db.create_all() but it still gives the same result.
this is my models.py.
from __init__ import db
from datetime import datetime
class Batch(db.Model):
__tablename__='batch'
batch_id = db.Column(db.String, primary_key=True)
#total = db.Column(db.Integer)
success = db.Column(db.Integer)
failure = db.Column(db.Integer)
folder = db.Column(db.String(15))
email = db.Column(db.String(20))
detail = db.relationship('Conversion', backref='details',lazy='dynamic')
platform = db.relationship('Platform', backref='pub_data', lazy = 'dynamic')
def __init__(self,batch_id,success,failure,folder,email):
self.batch_id = batch_id
self.success = success
self.failure = failure
self.folder = folder
self.email = email
class Conversion(db.Model):
__tablename__ = 'conversion'
id = db.Column(db.Integer, primary_key=True)
batch_id = db.Column(db.String,db.ForeignKey('batch.batch_id'))
file_names = db.Column(db.String)
status = db.Column(db.String(6))
error = db.Column(db.Text)
res_prop = db.Column(db.Integer)
def __init__(self,batch_id,file_names,status,res_prop,error=None):
self.batch_id = batch_id
self.file_names = file_names
self.status = status
self.error = error
self.res_prop = res_prop
class Platform(db.Model):
__tablename__ = 'platform'
id= db.Column(db.Integer,primary_key=True)
batch_id = db.Column(db.String, db.ForeignKey('batch.batch_id'))
title = db.Column(db.String)
pub_date = db.Column(db.DateTime)
def __init__(self,batch_id,title):
self.batch_id = batch_id
self.title = title
self.pub_date = datetime()
And here is my create_db.py
from modules import models
from modules import db
from migrate.versioning import api
from modules.default_config import SQLALCHEMY_DATABASE_URI , SQLALCHEMY_MIGRATE_REPO
import os.path
db.create_all()
db.session.commit()
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, api.version(SQLALCHEMY_MIGRATE_REPO))
on changing
from __init__ import db
to
from modules import db
in models.py it worked.
when running flask application from outside package one needs to import everything from the package itself and not the individual modules.

SQLAlchemy generating query in loop with contains

I'm building a web app in Flask that involves some SQLAlchemy. I have a function "get_team()" that is driving me bonkers.
def get_team(playerlist)
cond = and_(*[Team.users.contains(p) for p in playerlist ])
q = Team.query.filter(cond)
...
I keep getting the error: "AttributeError: 'unicode' object has no attribute '_sa_instance_state'". Here's what the models look like:
class Team(db.Model):
__tablename__ = 'teams'
id = db.Column(db.Integer, primary_key=True)
users = association_proxy("user_associations", "user", creator=lambda u: Teaming(user=u))
def __repr__(self):
s = ""
for u in self.users:
s = s + u.username + ", "
return "Team {tid}: {users_string}".format(tid = self.id, users_string=s)
class Teaming(db.Model):
__tablename__ = 'teaming'
team_id = db.Column(db.Integer, db.ForeignKey('teams.id'), primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
user = db.relationship("User", backref="team_associations")
team = db.relationship("Team", backref="user_associations")
def __repr__(self):
return "".format(uid = self.user_id, tid = self.team_id)
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean, default=False)
teams = association_proxy("team_associations", "team", creator = lambda t: Teaming(team=t))
Any direction would be greatly appreciated!
Most likely cause is that playerlist is not a list of User instances, but some strings (maybe names). contains works only on model instances. If you would like to work with other attributes, then use any.
def get_team_of_players(playerlist):
cond = and_(*[Team.users.contains(p) for p in playerlist])
q = Team.query.filter(cond)
return q
p1, p2 = db.session.query(User).get(1), db.session.query(User).get(2)
q = get_team_of_players([p1, p2]).all()
def get_team_of_usernames(usernames):
cond = and_(*[Team.users.any(User.username == p) for p in usernames])
q = Team.query.filter(cond)
return q
p1, p2 = 'user1', 'user2'
q = get_team_of_usernames([p1, p2]).all()

Categories

Resources