flask-sqlalchemy db.create_all() not creating helper/auxiliary table - flask

I am using flask-sqlalchemy in my application and have created below models. I am creating many to many relationship for Users and Subscription table, and tried to create helper table as User_Subscription.
After creating this model, when i run db.create_all() in command line, it is creating only 3 tables in database (tables having db.Model) but not creating helper table (User_Subscription) at all. It is not giving any error either.
Could someone please advise what's going wrong here?
I already searched a lot on google and stackoverflow, but I can't find answer where anyone has faced this problem where helper table (via db.table()) is not being created.
There was one issue from someone where they had somewhat similar problem, but he was facing as he wanted to do across multiple database.
I am doing on same database.
class Subscription(db.Model):
__tablename__ = "subscription"
id = db.Column(db.Integer, primary_key=True)
subscription_name = db.Column(db.String(100), unique=True, nullable=False)
User_Subscription = db.table('user_subscription',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('subscription_id', db.Integer, db.ForeignKey('subscription.id')),
db.Column('subscription_status', db.String(20), nullable=False, default='Active'))
class Users(db.Model, UserMixin):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(50), unique=False, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
date_created = db.Column(db.DateTime, default=datetime.datetime.utcnow)
date_updated = db.Column(db.DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
user_status_id = db.Column(db.String(2), db.ForeignKey('user_status.id'))
subscriptions = db.relationship('Subscription', secondary=User_Subscription, backref= db.backref('subscriptions', lazy=True))
def __repr__(self):
return f"Users('{self.firstname}', '{self.email}')"
class User_Status(db.Model):
__tablename__ = "user_status"
id = db.Column(db.String(2), primary_key=True)
status_desc = db.Column(db.String(20), unique=True, nullable=False)
users_status = db.relationship('Users', backref='usersofstatus')
Expected Result - 4 tables to be created in database.
Actual Result - Only 3 tables are being created. User_Subscription (Helper table for many to many relationship) is not being created.

After few hours of frustration, i found that i had a typo, i was using db.table instead of db.Table. So posting this answer in case it can help someone.

New to SQLAlchemy myself but it appears you are not inheriting from db.Model when creating User_Subscription. Why not make it a class?
class User_Subscription(db.Model):

Related

Flask-alchemy many to many relationship between separate packages

I have two tables Member and Posts. Respective classes are declared into separate models.py modules, that belong to separate packages members and posts.
post package - models .py
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer(), primary_key=True)
subject = db.Column(db.Text, nullable=False, unique=True, index=True)
body = db.Column(db.Text)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
category_id = db.Column(db.Integer(), db.ForeignKey('categories.id'))
tags = db.relationship('Tag', secondary=post_tags, lazy='subquery', backref=db.backref('post'))
authors = db.relationship('Member', secondary=member_posts, lazy='subquery', backref=db.backref('post'))
def __init__ (self,**kwargs):
super(Post, self).__init__(**kwargs)
members package - models .py
class Member(db.Model):
__tablename__ = 'members'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(50, collation='NOCASE'), nullable=False)
last_name = db.Column(db.String(50, collation='NOCASE'), nullable=False)
phone = db.Column(db.String(15))
twitter = db.Column(db.String(15))
avatar = db.Column(db.String(255), default='avatar.png')
# Relationships
field = db.relationship('Field', secondary=members_fields, lazy='subquery', backref=db.backref('member'))
position = db.relationship('Position', secondary=members_positions, lazy='subquery', backref=db.backref('member'))
def __init__ (self,**kwargs):
super(Member, self).__init__(**kwargs)
Those tables are connected with Many to Many relationship, and associative table member_posts is located along with posts class.
posts package - models .py
member_posts = db.Table('member_posts',
db.Column('member_id', db.Integer, db.ForeignKey('members.id'), primary_key=True),
db.Column('post_id', db.Integer, db.ForeignKey('posts.id'), primary_key=True)
)
When I send send request, debugger throws the following error:
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Post->posts, expression 'Member' failed to locate a name ('Member'). If this is a class name, consider adding this relationship() to the <class 'eierc.posts.models.Post'> class after both dependent classes have been defined.
Can anyone explain, hat is the problem and how to fix it?

How to set ManyToOne relationship in Flask- SQL alchemy?

I am new to Flask and SQLalchmey. I am trying to crate two tables and establish a manytoone relationship between them.
Here is what I did.
table_hub
class Hub(db.Model):
__tablename__ = 'hub'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(),nullable=False,unique=True)
tbl_vehicle
class vehileMaster(db.Model):
__tablename__ = 'res.vehicle'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
hub_id = db.Column(db.Integer,db.ForeignKey('hub.id'))
hub = db.relationship('Hub')
Here is what I need to achieve,
while creating a new vehicle in table res.vehicle I need to choose a hub from the list of hubs.
I don't know whether what i already did is correct or not.
The standard way of implementing a foreign key relationship would be:
class Hub(db.Model):
__tablename__ = 'hub'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), nullable=False,unique=True)
vehicles = db.relationship('res.vehicle', backref='hub', lazy=True)
class vehicleMaster(db.Model):
__tablename__ = 'res.vehicle'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
hub_id = db.Column(db.Integer, db.ForeignKey('hub.id'))

Flask_sqlalchemy many to many query

I have created the following models:
tag_post = db.Table('tag_post',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
db.Column('post_id', db.Integer, db.ForeignKey('post.id'), primary_key=True))
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(180))
body = db.Column(db.Text, nullable=False)
tags = db.relationship('Tag', secondary=tag_post, backref=db.backref('posts_associated', lazy="dynamic"))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(20))
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('Post', backref='author', lazy='dynamic')
How can I query all the posts tagged with a tag, by using the tag.id?
Thanks in advance
The solution is to use a join.
You want all posts that meet a condition. The query should therefore start with the table Post.
Post.query
Then you bind the table posts with your join table using the two columns that should fit. In this case the column post_id in the tag_post table and id in the Post table. Since you use your association table directly, the columns used are referenced using the name via the attribute c.
Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)
Then you filter the second column of your join table based on your condition.
tag_id = 1
Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)\
.filter(tag_post.c.tag_id == tag_id)
Since you want all posts and not just one, close the request with all().
tag_id = 1
tagged_posts = Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)\
.filter(tag_post.c.tag_id == tag_id)\
.all()
The following is a detailed query with the same result, which also includes the third table.
tag_id = 1
tagged_posts = Post.query\
.join(tag_post, tag_post.c.post_id == Post.id)\
.join(Tag, tag_post.c.tag_id == Tag.id)\
.filter(Tag.id == tag_id)\
.all()

How to record to record to a database with one-to-many relationship?

I am trying to do a small project, but have some difficulties around database structure in SQLAlchemy. I have two database models (code below).
User model is created and added to the database during the registration form.
Then I need to find a way to add Clients for loggedin user from his profile.
Question:
How do I do that? I need to create a record specifically for the logged-in user. So that when I display them (his clients)- they are only displayed to that specific user.
class User(UserMixin, db.Model):
tablename = 'user'
id = db.Column(db.Integer, primary_key=True)
company_name = db.Column(db.String(120), index=True, unique=False)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
clients = db.relationship('Client', backref='invoice_clients', lazy='dynamic')
class Client(db.Model):
tablename = 'client'
id = db.Column(db.Integer, primary_key=True)
client_name = db.Column(db.String(140))
client_company = db.Column(db.String(140))
client_email = db.Column(db.String(140))
invoice_amount = db.Column(db.Integer)
service_description = db.Column(db.String)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
I expect that the when a user adds a client from his profile page - it will be recorded in the database only for him.
First of all, I believe you have the backref parameter backwards. That is the property you can use on the referenced objects to "get back" to the current class. So it should probably look like this:
class User(UserMixin, db.Model):
__tablename__ = 'user'
clients = db.relationship('Client', backref='user', lazy='dynamic')
As to your question about adding clients for a specific user, there are two ways you can approach it. You can do it manually:
# Or flask_login, or whatever you're using for user management
from flask_security import current_user
new_client = Client(client_name="Lancelot", user_id=current_user.id)
db.session.add(new_client)
db.session.commit()
Or you can simply use SQLAlchemy to append the client to your user. The declared foreign key will cause the id to be assigned automatically:
from flask_security import current_user
new_client = Client(client_name="Sir Bedivere")
current_user.clients.append(new_client)
db.session.commit()

How to use order by in flask sqlalchemy for date attribute

I have a flask application and I am using flask sqlalchemy.I have two classes like below:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
diaries = db.relationship('Diary', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
class Diary(db.Model):
id = db.Column(db.Integer, primary_key=True)
diary_date= db.Column(db.DateTime, nullable=False, default=datetime.now())
emotion = db.Column(db.String(10))
note = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Diary('{self.diary_date}', '{self.emotion}','{self.note}')"
I want to order by using diary_date and then take first seven records.I want to show frequent emotion in a week to user.For order by I used following query:
>>> records=(db.session.query(Diary).filter_by(Diary.user_id=User.id).join(Diary
,User.diaries).order_by(Diary.diary_date))
It is giving an error
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
Is the query wrong?Can you suggest a better query? I am new to sqlalchemy sorry if the question is too dumb.
change filter_by to filter and replace = with ==. It will resolve your error:
db.session.query(Diary).filter(Diary.user_id==User.id).join(Diary,User.diaries).order_by(Diary.diary_date)
And this gives you:
SELECT diary.id AS diary_id, diary.diary_date AS diary_diary_date, diary.emotion AS diary_emotion, diary.note AS diary_note, diary.user_id AS diary_user_id
FROM user JOIN diary ON user.id = diary.user_id
WHERE diary.user_id = user.id ORDER BY diary.diary_date
But as you can see WHERE diary.user_id = user.id is unnecessary as it is covered by JOIN expression. It can be safely removed.
Also you can change default=datetime.now() to default=datetime.now. Thanks to that diary_date will be set to time the Diary object is created and not when Diary was parsed by interpreter (all objects would get the same default time).