How to get rid of this error sqlalchemy.exc.ArgumentError - python

Hello i would like to know how to get rid of this error. Here are my my tables
#login_menager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
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)
posts = db.relationship('Post', backref='author', lazy=True)
user_comments = db.relationship('Comment', backref='author_comment', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
class Comment(db.Model):
id = db.Column(db.Integer, primary_key = True)
body = db.Column(db.Text)
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
#post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
comment_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Comment('{self.body}')"
When i add these lines:
if comment_form.validate_on_submit():
reply = Comment(body=comment_form.comment_on_form.data, author_comment=current_user)
db.session.add(reply)
db.session.commit()
replies = Comment.query.filter_by(author_comment=current_user).order_by(Comment.timestamp.desc()).all()
return render_template('home.html', posts=posts, title='Home', form=form, comment_form=comment_form, replies=replies)
I get this error:
sqlalchemy.exc.ArgumentError: Mapped instance expected
for relationship comparison to object.
Classes, queries and other SQL elements are not accepted in this context;
for comparison with a subquery, use Comment.author_comment.has(**criteria).
With trackback:
https://raw.githubusercontent.com/RealdoBeja98/endi-s_project/main/README.md
I would appreciate any help. Thank you

Related

Flask: sqlalchemy.exc.OperationalError

So, I'm trying to create a blog that has users who can create posts, within any post there should be comments written by the users.
That's my code:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
email = db.Column(db.String(120), nullable=False, unique=True)
password = db.Column(db.String(60), nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
posts = db.relationship('Post', backref='author', lazy=True)
comments = db.relationship('Comment', backref='commentauthor', lazy=True)
def __repr__(self):
return f"User('{self.username}','{self.email}','{self.image_file}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
comments = db.relationship('Comment', backref='postcontainer', lazy=True)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Comment('{self.content}', '{self.date_posted}')"
Also the code at my route:
#app.route("/", methods=['POST', 'GET'])
def home():
page = request.args.get('page', 1, type=int)
posts = Post.query.order_by(Post.date_posted.desc()).paginate(page=page, per_page=5)
cpost = CreatePost()
if cpost.validate_on_submit():
post = Post(title=cpost.title.data, content=cpost.content.data, author=current_user)
db.session.add(post)
db.session.commit()
return redirect(url_for('home'))
ccomment = CreateComment()
comments = Comment.query.all()
if ccomment.validate_on_submit():
comment = Comment(content=ccomment.content.data)
db.session.add(comment)
db.session.commit()
return redirect(url_for('home'))
return render_template('home.html', posts=posts, cpost=cpost, ccomment=ccomment, comments=comments)
I end up getting this error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such
table: comment [SQL: SELECT comment.id AS comment_id,
comment.date_posted AS comment_date_posted, comment.content AS
comment_content, comment.post_id AS comment_post_id, comment.user_id
AS comment_user_id FROM comment] (Background on this error at:
http://sqlalche.me/e/e3q8)
Traceback (most recent call last)
How can I fix this?
You need to create the comment table in your database, if you are using flask-sqlalchemy extension then you only need to call this function https://flask-sqlalchemy.palletsprojects.com/en/2.x/api/#flask_sqlalchemy.SQLAlchemy.create_all
https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/
Go to your python shell window and type:
from name import db
db.create_all()
name is the name of your project.

I am getting "AttributeError: 'int' object has no attribute 'filter'

I want this to be able to filter post by the CURRENT USER and delete it. Someone told me to use .WHERE instead of .FILTER but neither of them are working and I get an Attribute Error. How can I get this working?
By the way I am able to delete ALL user post with just db.session.query(Post).delete() but I want it so it only deletes posts for CURRENT_USER.ID (the user that is currently logged into my session)
I added my current models:
#login_required
def delete_all_post():
if current_user.is_authenticated:
db.session.query(Post).delete().filter(Post.user_id == current_user.id)
db.session.commit()
flash('All of your posts has been deleted!', 'success')
return redirect(url_for('main.home'))```
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', {self.date_posted}')"
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(16), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
delete() return True/ False which is 0 or 1 which is int so you cannot do filter over it
try:
db.session.query(Post).filter(Post.user_id == current_user.id).delete()

How to display list of users who have liked a post in Flask app?

I am new to Flask and I have created a social media blog using Flask by following videos of Corey Schafer and Miguel Grinberg, I have incorporated additional functionalities such as Liking a post and Commenting on a post. All of the functionalities that I have incorporated are functioning properly but I cannot view the users who have liked a post.
here is my routes.py file that has the like and ViewLikers route
#app.route('/like/<int:post_id>/<action>')
#login_required
def like_action(post_id, action):
post = Post.query.filter_by(id=post_id).first_or_404()
if action == 'like':
current_user.like_post(post)
db.session.commit()
if action == 'unlike':
current_user.unlike_post(post)
db.session.commit()
return redirect(request.referrer)
#app.route('/like/<int:post_id>/viewLikes')
#login_required
def viewLikers(post_id):
post = Post.query.get_or_404(post_id)
return render_template('viewLikes.html', likers=post.get_likers())
Here is my models.py file
class PostLike(db.Model):
__tablename__ = 'PostLike'
id = db.Column(db.Integer, primary_key=True)
users_id = db.Column(db.Integer, db.ForeignKey('user.id'))
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
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)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
followed = db.relationship(
'User', secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'), lazy='dynamic')
liked = db.relationship(
'PostLike',
foreign_keys='PostLike.users_id',
backref='user', lazy='dynamic')
def like_post(self, post):
if not self.has_liked_post(post):
like = PostLike(users_id=self.id, post_id=post.id)
db.session.add(like)
def unlike_post(self, post):
if self.has_liked_post(post):
PostLike.query.filter_by(
users_id=self.id,
post_id=post.id).delete()
def has_liked_post(self, post):
return PostLike.query.filter(
PostLike.users_id == self.id,
PostLike.post_id == post.id).count() > 0
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), unique=True, nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
likes = db.relationship('PostLike', backref='post', lazy='dynamic')
comments = db.relationship('Comment', backref='title', lazy='dynamic')
def get_likers(self):
return PostLike.query.filter_by(users_id =User.id, post_id=self.id)
But when I click on the viewLikes button in the template it gives me an error stating Function doesn't return any view
Simple error. In the last method you haven't returned the render_template. return render_template('')
Also call .first() on your post object

Post object with many recipients

I have three models : user, houses and a post.
I am trying to assign a post to one author and mutliple recipients, but I do not know how to do it.
I reckon it may have to do with relationships between tables...
These are my models
lettings = db.Table('lettings',
db.Column('tenant_id', db.Integer, db.ForeignKey('user.id')),
db.Column('property_id', db.Integer, db.ForeignKey('house.id'))
)
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
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))
lettings = db.relationship("Houses",secondary=lettings,lazy="dynamic", backref=db.backref("tenants",lazy="dynamic"))
posts_sent = db.relationship('Post',
foreign_keys='Post.sender_id',
backref='author', lazy='dynamic')
posts_received = db.relationship('Post',
foreign_keys='Post.recipient_id',
backref='recipient', lazy='dynamic')
last_post_read_time = db.Column(db.DateTime)
def haslived(self,house):
if not self.isliving(house):
self.lettings.append(house)
def unlived(self, house):
if self.isliving(house):
self.lettings.remove(house)
def isliving(self, house):
return self.lettings.filter_by(id=house.id).first()
class Post(db.Model):
__tablename__ = 'post'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(32))
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'))
house_id = db.Column(db.Integer, db.ForeignKey('house.id'))
__searchable__= ['body']
def __repr__(self):
return '<Post {}>'.format(self.body)
class Houses(db.Model):
__tablename__ = 'house'
id = db.Column(db.Integer, primary_key=True,index=True)
address = db.Column(db.String(120))
postcode = db.Column(db.String(120),index=True)
licence_holder = db.Column(db.String(140),index=True)
__searchable__=['address']
posts = db.relationship('Post', backref='letting', lazy='dynamic')
def __repr__(self):
return '<House {}>'.format(self.address)
And this is my routes code snippet:
#bp.route('/house/<address>/ask',methods=['GET', 'POST'])
#login_required
def ask(address):
house = Houses.query.filter_by(address=address).first_or_404()
form = PostForm()
if form.submit.data and form.validate_on_submit():
post = Post(body=form.body.data,title=form.title.data,author=current_user,letting=house,recipient={I do not know what to write here})
db.session.add(post)
db.session.commit()
flash('Your post is now live!')
return redirect(url_for('main.house', address=house.address))
return render_template('ask.html', title='Ask a question about {}'.format(house.address),form=form,house=house)
My objective is to create a post object which will have only one sender but multiple recipients.
Thank you for your help.
Yes, as somebody above correctly pointed out, this can be done using many-to-many relationship from SQLalchemy.
I got the answer myself, that's how i modified the code:
My models:
lettings = db.Table('lettings',
db.Column('tenant_id', db.Integer, db.ForeignKey('user.id')),
db.Column('property_id', db.Integer, db.ForeignKey('house.id'))
)
class User(UserMixin, db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
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))
reviews = db.relationship('Review', backref='author', lazy='dynamic')
checklists = db.relationship('Checklist', backref='author', lazy='dynamic')
about_me = db.Column(db.String(140))
lettings = db.relationship("Houses",secondary=lettings,lazy="dynamic", backref=db.backref("tenants",lazy="dynamic"))
posts_sent = db.relationship('Post',
foreign_keys='Post.sender_id',
backref='author', lazy='dynamic')
last_post_read_time = db.Column(db.DateTime)
def new_posts(self):
last_read_time = self.last_post_read_time or datetime(1900, 1, 1)
return Post.query.filter_by(recipients=self).filter(
Post.timestamp > last_read_time).count()
def haslived(self,house):
if not self.isliving(house):
self.lettings.append(house)
def unlived(self, house):
if self.isliving(house):
self.lettings.remove(house)
def isliving(self, house):
return self.lettings.filter_by(id=house.id).first()
def __repr__(self):
return '<User {}>'.format(self.username)
recipients = db.Table('recipients',
db.Column('recipient_id', db.Integer, db.ForeignKey('user.id')),
db.Column('post_id', db.Integer, db.ForeignKey('post.id'))
)
class Post(db.Model):
__tablename__ = 'post'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(32))
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
recipients = db.relationship("User",secondary=recipients,lazy="dynamic", backref=db.backref("posts_received",lazy="dynamic"))
house_id = db.Column(db.Integer, db.ForeignKey('house.id'))
__searchable__= ['body']
def __repr__(self):
return '<Post {}>'.format(self.body)
def add_recipient(self, recipient):
self.recipients.append(recipient)
class Houses(db.Model):
__tablename__ = 'house'
id = db.Column(db.Integer, primary_key=True,index=True)
address = db.Column(db.String(120))
postcode = db.Column(db.String(120),index=True)
licence_holder = db.Column(db.String(140),index=True)
__searchable__=['address']
posts = db.relationship('Post', backref='letting', lazy='dynamic')
reviews = db.relationship('Review', backref='house', lazy='dynamic')
checklists = db.relationship('Checklist', backref='house', lazy='dynamic')
latitude=db.Column(db.Float(precision=32,decimal_return_scale=None),index=True)
longitude=db.Column(db.Float(precision=30,decimal_return_scale=None),index=True)
def __repr__(self):
return '<House {}>'.format(self.address)
And you add all the recipients to a post once its uploaded by a different user using list comprehension:
Post(body=form.body.data,title=form.title.data,author=current_user,letting=house)
[post.add_recipient(recipient) for recipient in house.tenants.all()]
db.session.add(post)
db.session.commit()

AttributeError: 'InstrumentedList' object has no attribute 'get'

In rendering an html template, the minutes_id is not being passed through correctly. It's throwing the error: "AttributeError: 'InstrumentedList' object has no attribute 'get'". I'm not sure how to fix this.
This is the line of code tripping me up.
minutes = club.minutes.get(minutes_id) #GET THE Minutes for specific DAY
routes.py:
#clubs.route("/view_minutes/<int:user_id>/<int:club_id>", methods=['GET', 'POST'])
#login_required
def view_minutes(user_id, club_id):
club = Club.query.get_or_404(club_id)
user = User.query.get_or_404(user_id)
minutes = club.minutes
#if click "export" -->
#return render_pdf(url_for('minutes_pdf', user_id=user_id, club_id=club_id))
return render_template('view_minutes.html', title='View', user=user, club=club, minutes=minutes)
#clubs.route("/minutes_pdf/<int:user_id>/<int:club_id>/<int:minutes_id>.pdf", methods=['GET', 'POST'])
#login_required
def minutes_pdf(user_id, club_id, minutes_id):
club = Club.query.get_or_404(club_id)
user = User.query.get_or_404(user_id)
minutes = club.minutes.get(minutes_id) #GET THE Minutes for specific DAY
return render_template('view_minutes_pdf.html', club=club, minutes=minutes)
models.py
user_club_assoc_table = db.Table('user_club_assoc_table',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('club_id', db.Integer, db.ForeignKey('club.id')))
roles = db.relationship('Role', secondary='user_roles',
backref=db.backref('users', lazy='dynamic'))
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(15), nullable=False)
lastname = db.Column(db.String(15), nullable=False)
email = db.Column(db.String(60), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
role = db.Column(db.Integer(), nullable=False, default=ROLES['student'])
clubs = db.relationship('Club', secondary=user_club_assoc_table)
def __repr__(self):
return f'{self.firstname} {self.lastname}' #return f'User(firstname={self.firstname!r}, lastname={self.lastname!r})'
class Club(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
members = db.relationship('User', secondary=user_club_assoc_table)
minutes = db.relationship('Minutes', backref='club')
def __repr__(self):
return f'{self.name}'#Club(name={self.name!r})
class Minutes(db.Model):
id = db.Column(db.Integer, primary_key=True)
club_id = db.Column(db.Integer, db.ForeignKey('club.id'))
date = db.Column(db.Date, nullable=False) #0000-00-00
time = db.Column(db.Time) #00:00:00
location = db.Column(db.String(100), nullable=False)
attendance = db.relationship('Attendance', backref='minutes', lazy=True) #check code
purchase = db.Column(db.Text)
purchasemotion = db.Column(db.Text)
fundraiser = db.Column(db.Text)
fundmotion = db.Column(db.Text)
minute = db.Column(db.Text, nullable=False) #notes
def __repr__(self):
return f'{self.club_id} {self.date}'
class Attendance(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
student_name = db.Column(db.String(35), nullable=False)
present = db.Column(db.Boolean, default=False) #set correctly
minutes_id = db.Column(db.Integer, db.ForeignKey('minutes.id'))
In the url you are already capturing minute_id why don't you query directly
Minutes.query.get_or_404(minute_id)

Categories