Sqlalchemy User Product Reviews Relation model deisgn - python

Need models so that a User can have a Products and Users can leave Reviews on Products made by other users. I was thinking having a one to many relationship from products to reviews but then how do which users left which review. This is what i have so far.
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
products = db.relationship('Product', backref='products',
lazy='dynamic')
class Review(db.Model):
id = db.Column(db.Integer(), primary_key=True)
stars = db.Column(db.String(255))
description = db.Column(db.String(255))
class Product(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
id = db.Column(db.Integer(), primary_key=True)

You just need to add foreign keys for User and Product into your Review table:
class Review(db.Model):
# ...
product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
You can also then add backrefs for Reviews on to your User and Product, and you can filter the user.reviews by product_id.

I'm imagining setting it up like this (with the new one-to-many included as well - I think I've got that right). You should know the product's ID at the time you're creating the entry in the Python code, so you can simply add it in. I don't think you would necessarily need to create a relationship for that.
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), unique=True)
products = db.relationship('Product', backref='user',
lazy='dynamic')
reviews= db.relationship("Review", backref="user", lazy='dynamic')
class Review(db.Model):
id = db.Column(db.Integer(), primary_key=True)
product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
stars = db.Column(db.String(255))
description = db.Column(db.String(255))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class Product(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
id = db.Column(db.Integer(), primary_key=True)
I changed a line in your User class. You had
products = db.relationship('Product', backref='product',
lazy='dynamic')
But I think it's supposed to be
products = db.relationship('Product', backref='user',
lazy='dynamic')

Related

Flask-SQLAlchemy: User role Models and relationship

I am trying to create a Flask-SqlAlchemy database model and need users to be linked to a single role. Example roles: "User", "Admin", "Moderator".
Surely I could use a simple relatioship, which just adds a user_role_id Column to the User, but I would also like to track the last modification.
class User:
id = db.Column(db.Integer, primary_key=True)
class UserRole:
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
class UserRoleLink(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
user_role_id = db.Column(db.Integer, db.ForeignKey("user_role.id"), primary_key=True)
last_modified = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)
How do I complete this model with the required relationships? Also I would like to ensure, that a User can only have one Role, but Roles can be used as often as required.
Thank you in advance!
I think it should works for you:
class User:
id = db.Column(db.Integer, primary_key=True)
class UserRole:
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False, unique=True)
role_link = db.relationship('UserRoleLink', cascade='all, delete-orphan', uselist=False)
class UserRoleLink(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
user_role_id = db.Column(db.Integer, db.ForeignKey("user_role.id"), primary_key=True)
last_modified = db.Column(db.DateTime, nullable=False, default=datetime.now, onupdate=datetime.now)

Foreign keys, relationship between models in sqlalchemy flask

I have these two models:
class User(db.Model, UserMixin):
__tablename__ = 'users'
__table_args__ = (
PrimaryKeyConstraint('id',),
)
id = db.Column(db.Integer, primarky_key=True)
username = db.Column(db.String, unique=True, nullable=False)
email = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
class Review(db.Model):
__tablename__ = 'reviews'
__table_args__ = (
PrimaryKeyConstraint('id', ),
)
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
I wanted to create a relationship between these two tables so that when a user writes a review it should go to Review model and it has a relation with user_id in Users model. I have tried lots of answers but they are returning different kinds of errors I am confused, can anybody help?
You can use db.relationship to create a one-to-many relationship between users and reviews.
class User(db.Model, UserMixin):
__tablename__ = 'users'
__table_args__ = (
PrimaryKeyConstraint('id',),
)
id = db.Column(db.Integer, primarky_key=True)
username = db.Column(db.String, unique=True, nullable=False)
email = db.Column(db.String, unique=True, nullable=False)
password = db.Column(db.String, nullable=False)
reviews = db.relationship('Review', backref='user', cascade='all, delete, delete-orphan')
class Review(db.Model):
__tablename__ = 'reviews'
__table_args__ = (
PrimaryKeyConstraint('id', ),
)
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
This would allow for user.reviews and review.user
Try this:
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship(User, backref='user_reviews', lazy=True)
And read the documentation.

Query a single table with relationship database Flask-SQLAlchemy

I've got three tables: User, Role, Department
I want to query all the user with selected following filters:
Department.name , Role.name and User.degree
I can't find a solution to this problem, any suggestion would be great!
Here's my models simplified:
class User(UserMixin, db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
password_hash = db.Column(db.String(128))
degree = db.Column(db.String(20),default=None)
department_id = db.Column(db.Integer, db.ForeignKey('departments.id'))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
class Department(db.Model):
__tablename__ = "departments"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(sqlalchemy.types.NVARCHAR(100), unique=True)
user = db.relationship('User', backref='department',
lazy='dynamic')
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(sqlalchemy.types.NVARCHAR(100), unique=True)
users = db.relationship('User', backref='role',
lazy='dynamic')
session.query(User).filter(
User.department.has(name='some_name)).filter(
User.role.has(name='some_role')).filter(
User.degree == 'some_degree')
It's a simple query with joins. You can modify "department" with your department filter and "role" with the same. You should modify the select part (session.query(User.id)) with the fields you want.
users = (session.query(User.id).join(Department, Department.user == User.id).join(Role, Role.user == User.id).filter(Department.name=="department").filter(Role.name=="role").group_by(User.id))

Unable to delete parent record in one to many relationship - Flask-SqlAlchemy

I've created to 3 simple model with flask-sqlalchemy with one to many relationship. Here is the code for models:
class UsersModel(BaseModel, UserMixin):
__tablename__ = 'user'
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
confirmed_at = db.Column(db.DateTime())
info = db.relationship('UserInfoModel', backref="user", cascade="all, delete" , lazy='dynamic')
notes = db.relationship('NotesModel', backref="owner", cascade="all, delete" , lazy='dynamic')
class UserInfoModel(db.Model):
__tablename__ = 'user_info'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
first_name = db.Column(db.String(55))
last_name = db.Column(db.String(55))
age = db.Column(db.Integer)
profession = db.Column(db.String(255))
class NotesModel(BaseModel):
__tablename__ = 'notes'
title = db.Column(db.String(255), nullable=False)
desc = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
I can insert and retrive relational data without any problem but when I'm trying to delete a user it should also delete notes & info rather it gives error and don't let me delete. Here is the error that I see: http://prntscr.com/ek5cx1
But if I delete notes & info and then try to delete user it works. It's doing the reverse. I tried using 'delete-orphan' but didn't worked. I have read the documentation and read some blog about it but nothing helps. Am I wrong about declaring the relation? If so please help me to implement this or help me to find error within my code.
Appriciate your help, Thanks
Update: After adding delete-orphan I can delete data from session but not form phpmyadmin.
i think you want your relationships defined opposite how you have them, so like this:
class UsersModel(BaseModel, UserMixin):
__tablename__ = 'user'
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
confirmed_at = db.Column(db.DateTime())
class UserInfoModel(db.Model):
__tablename__ = 'user_info'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
first_name = db.Column(db.String(55))
last_name = db.Column(db.String(55))
age = db.Column(db.Integer)
profession = db.Column(db.String(255))
user = db.relationship('User',uselist=False, cascade='all, delete-orphan',backref=db.backref('info', uselist=False))
class NotesModel(BaseModel):
__tablename__ = 'notes'
title = db.Column(db.String(255), nullable=False)
desc = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User',uselist=False, cascade='all, delete-orphan',backref=db.backref('notes'.lazy='dynamic'))
use this way
cascade="all,delete"

How to specify more than 1 backref

I have a 3 tables: users, posts and comments. I'm trying to get username of comment author.
This is my models.py:
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.Integer, unique=True, index=True)
comments = db.relationship('Comment', backref='author', lazy='dynamic')
#i'm trying to:
comment_author = db.relationship('Comment', backref='comment_author_username', lazy='dynamic')
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(32), index=True)
comments = db.relationship('Comment', backref='post', lazy='dynamic')
body = db.Column(db.Text)
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
class Comment(db.Model):
__tablename__ = 'comments'
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text)
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
#im trying to do:
#comment_author_username = db.Column(db.String(64), db.ForeignKey('users.username'))
but getting an error:
AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship User.comments - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
If i'm using in template {{comment.author_id}} it works properly(shows comment author id), but {{comment.author_id.username}} shows nothing. How i can get comment author username?
You are making TWO relation from table User (comments, comment_author) to table Comment (That basically they are the same).
The author_id in table Post has a db.ForeignKey('users.id') but there is no refer to table Post in your User table.
Basically what you want is, There are some posts that they have their own author, and for each post there are some comments that they have also their authors. The relation between your Post and User is One-To-Many and the relation between your Post and Comment is also One-To-Many. The Relation between Comment and User is One-To-Many. By sqlalchemy, Your Tables will be like below:
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.Integer, unique=True, index=True)
posts = db.relationship('Post', backref='poster', lazy='dynamic')
comments = db.relationship('Comment', backref='commenter', lazy='dynamic')
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(32), index=True)
body = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
comments = db.relationship('Comment', backref='comment_on_post', lazy='dynamic')
class Comment(db.Model):
__tablename__ = 'comments'
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
and for adding data, you can do like:
s = db.session
user = User(username='Alex')
post = Post(title='First try', body='This is my first try!')
comment = Comment(body='This is a useful post!')
user.posts.append(post)
user.comments.append(comment)
post.comments.append(comment)
s.add(user)
s.add(post)
s.add(comment)
s.commit()
s.close()
and for retrieve data:
s = db.session
comments = models.Comment.query.all()
for c in comments:
print c.user_id
s.close()

Categories

Resources