'list' object has no attribute 'id' - python

i get 'list' object has no attribute 'id' error. I dont know why.
#posts.route("/post/<int:post_id>", methods=['GET','POST'])
#login_required
def course_post(post_id):
post=Post.query.get_or_404(post_id)
chapters=Chapter.query.filter_by(post_id=post_id).all()
chapter_id = chapters.id
videos=Videos.query.filter_by(chapter_id=chapter_id).all()
return render_template('course.html', title=post.course_name, post=post, chapters = chapters)
class Chapter(db.Model):
id = db.Column(db.Integer, primary_key= True)
chapter_no = db.Column(db.Integer)
chapter_name = db.Column(db.String(50))
chapter_desc = db.Column(db.String(50))
chapter_date = db.Column(db.DateTime, default=datetime.utcnow)
vi = db.relationship('Videos', backref='topic', lazy=True)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
def __repr__(self):
return f"Chapter('{self.chapter_no}', '{self.chapter_name}', '{self.chapter_desc}', '{self.chapter_date}', '{self.post_id}'"
class Videos(db.Model):
id = db.Column(db.Integer, primary_key= True)
video_no = db.Column(db.Integer)
video_name = db.Column(db.String(50), nullable=False, index=True)
video_file = db.Column(db.String(200))
yout_code = db.Column(db.String(200))
video_description = db.Column(db.Text(100))
uploaded_date = db.Column(db.DateTime, default=datetime.utcnow)
rating = db.Column(db.Integer())
chapter_id = db.Column(db.Integer, db.ForeignKey('chapter.id'), nullable=False)
c_v = db.relationship("Chapter", foreign_keys=chapter_id) #
def __repr__(self):
return f"Videos('{self.video_no}','{self.video_name}', '{self.video_file}', '{self.yout_code}', '{self.video_description}', '{self.uploaded_date}', '{self.rating}', '{self.chapter_id}'"
i am trying to get all the videos for each chapter in the Videos table using chapters.id as foreign key
Please what am i doing wrong ?

Try updating your function like this
#posts.route("/post/<int:post_id>", methods=['GET','POST'])
#login_required
def course_post(post_id):
post=Post.query.get_or_404(post_id)
chapters=Chapter.query.filter_by(post_id=post_id).all()
chapter_id = chapters and chapters[0].id
videos=Videos.query.filter_by(chapter_id=chapter_id).all()
return render_template('course.html', title=post.course_name, post=post, chapters = chapters)
Now it uses first chapter ID it founds. I don't know if this is something you want though.
If you want to get list of chapter ids you can do it like this
chapter_id = [c.id for c in chapters]
But I don't know how ORM library you are using handles filtering by lists.

I added this to the parent class (Chapter) of the model.py
medias = db.relationship('Videos', backref='Chapter', lazy='subquery')
The code below pulls the query and sub query of parent and child. This code does that:
chapters = db.session.query(Chapter).filter_by(post_id=post_id).all()
i.e:
#posts.route("/post/<int:post_id>", methods=['GET','POST'])
#login_required
def course_post(post_id):
post=Post.query.get_or_404(post_id)
#chapters=Chapter.query.filter_by(post_id=post_id).all()
chapters = db.session.query(Chapter).filter_by(post_id=post_id).all()
return render_template('course.html', title=post.course_name, post=post, chapters = chapters)
Then in my template, to loop the chapters and videos for each chapter in the template:
{% for v in chapters %}
<h7><span class="plus">+</span>{{ v.chapter_name }}</h7> <br><br>
<div class="descDiv">
{% for media in v.medias %}
<p class="desc">{{ media.video_name }}</p>
{% endfor %}
</div>
{% endfor %}

Related

{{ treatment.data }} jinja Treatment model does not have a data field. data not displaying

I ran into this issue while making this application to collect patient data at a dental clinic. I followed this tutorial. I can get some small things in the code to meet my requirement. But It just displays dots instead of the data. When I add {{ treatment.date }} It displays the date the information is created as expected. This is how it looks. When I add {{ treatment.data | pprint }} It dispalays the dot and prints Undefined. I haven't added the css styling yet.
<ul id="treatment">
{%for treatment in user.info%}
<li>{{ treatment.data }}</li>
{%endfor%}
</ul>
This is how it is written in the html
This is how I enter the data to the database
def home():
if request.method == 'POST':
treatment = request.form.get('treatment')
history = request.form.get('history')
future = request.form.get('future')
payment = request.form.get('payment')
if len(treatment) <1 :
flash('Treatment is too short', category='error')
elif len(history) <1 :
flash('History is too short', category='error')
elif len(future) <1 :
flash('Treatment plan is too short', category='error')
elif len(payment) <1 :
flash('Payment is too short', category='error')
else:
new_record=Info(treatment=treatment,history=history,future=future,payment=payment,user_id=current_user.id)
db.session.add(new_record)
db.session.commit()
flash('Record Added!', category='success')
return render_template("home.html", user=current_user)
This is the code in the models.py
from flask_login import UserMixin
from sqlalchemy.sql import func
class Info(db.Model):
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.DateTime(timezone=True), default=func.now())
history = db.Column(db.String(10000))
treatment = db.Column(db.String(10000))
future = db.Column(db.String(10000))
payment = db.Column(db.Integer)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(150))
tel = db.Column(db.Integer, unique=True)
nic = db.Column(db.Integer, unique=True)
info = db.relationship('Info')```
I hope someone can help.
I expect it to display the data regarding treatment,history,future and payment

cant commit() an updated data with sqlalchemy cant find whats wrong

hello my sqlalchemy just wont commit im pretty sure that my code is correct but i have no idea what why it wont commit
class Movie(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), unique=True, nullable=False)
year = db.Column(db.String(80), nullable=False)
description = db.Column(db.String(180), nullable=False)
rating = db.Column(db.String(80), nullable=False)
ranking = db.Column(db.String(80), nullable=False)
review = db.Column(db.String(256), nullable=False)
img_url = db.Column(db.String(1000), nullable=False)
def __repr__(self):
return f"id: {self.id} title: {self.title} year: {self.year} description:
{self.description} rating: {self.rating} " \
f"ranking {self.ranking} review: {self.review} img_url: {self.img_url}"
#app.route('/edit', methods=['GET','POST'])
def edit_movie():
movie_id = request.args.get('id')
form = Edit_Form()
print(movie_id)
if request.method == 'POST':
movie_update = Movie.query.filter_by(id=movie_id).first()
movie_update.rating = form.rating.data
movie_update.review = form.review.data
db.session.commit()
return redirect(url_for('home'))
return render_template('edit.html', form=form)
thats my html code
<form action="{{ url_for('edit_movie') }}" method="POST">
{{ form.csrf_token }}
<p>please put in your new rating</p>
{{ form.rating }}
<p>please write your review </p>
{{ form.review }}
{{ form.submit }}
</form>
it seems not to make any changes to the sql data
AttributeError: 'NoneType' object has no attribute 'rating'
movie_update = Movie.query.filter_by(id=movie_id).first()
isn't finding a Movie, and is returning None.
The "movie.update" object that you think you are creating, hasn't been created, whereby not only rating will fail as a method, but I am sur review, too. So, when that fails, nothing will commit

Creating a Full-Text Search in Flask [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am trying to relalize full-text search in flask, but nothing happend, there is nothing in traceback and web-application keep working. Please, could you advise me, where I should make some corrections, I try to realize this one first time and dont have such experience before.
event\forms.py
class SearchForm(FlaskForm):
query = StringField('search', validators=[DataRequired()], render_kw={"class": "form-control"})
submit = SubmitField('Submit', render_kw={'class': 'btn btn-secondary border-0'})
event\models.py
class Event(db.Model):
__searchable__ = ['title', 'description']
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, unique=True, primary_key=True)
title = db.Column(db.String(50), nullable=False)
genre = db.Column(db.String(100), nullable=True)
url = db.Column(db.String(100), unique=True, nullable=False)
date_start = db.Column(db.Date, nullable=True)
date_finish = db.Column(db.Date, nullable=True)
description = db.Column(db.String(150), nullable=True)
place = db.Column(db.String(50), nullable=True)
address = db.Column(db.String(100), nullable=True)
price = db.Column(db.String, nullable=True)
img_url = db.Column(db.String(100), nullable=True)
text = db.Column(db.Text, nullable=True)
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
category = db.relationship('Category', backref='events')
resource_id = db.Column(db.Integer, db.ForeignKey('resource.id'))
resource = db.relationship('Resource', backref='events')
event\views.py
#blueprint.before_request
def before_request():
g.search_form = SearchForm()
#blueprint.route('/search', methods = ['POST'])
def search():
if not g.search_form.validate_on_submit():
return redirect(url_for('event.index'))
return redirect(url_for('event.search_results', query = g.search_form.search.data))
#blueprint.route('/search_results/<query>')
def search_results(query):
search_str = f"%{form.search.data}%"
results = Event.query.filter(Event.name.ilike(search_str), Event.description.ilike(search_str))
return render_template('event/search_results.html',
query = query,
results = results)
event\search_results.html
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
{% if results %}
<h3>Here are some results</h3>
{% for result in results %}
{{ result }}
{% endfor %}
{% endif %}
{% endblock %}
Thanks a lot!
I see 2 issues.
On the '/search_results/' route, form.search.data is never defined. Since you included that as a url parameter, you can reference "query" directly in your sqlalchemy query.
The filter clause on your query is currently:
filter(Event.name.ilike(search_str), Event.description.ilike(search_str))
which translates to name and description are both like search_str. I'm assuming that you what you are really looking for is name or description are like search_str.
If that's the case, you can wrap the filter with an "or" clause.
filter(or_(Event.name.ilike(search_str), Event.description.ilike(search_str)))
https://docs.sqlalchemy.org/en/13/core/sqlelement.html#sqlalchemy.sql.expression.or_

order_by() a related table with Flask-SQLAlchemy

Here are my models:
class Entry(db.Model):
id = db.Column(db.Integer, primary_key=True)
manifest = db.Column(db.String, default=None, nullable=True)
name = db.Column(db.String, default=None, nullable=True)
actions = db.relationship('Action', backref='entry', lazy='dynamic')
class Action(db.Model):
id = db.Column(db.Integer, primary_key=True)
action_date = db.Column(db.DateTime, default=datetime.utcnow, nullable=True)
location = db.Column(db.String, default=None, nullable=True)
entry_id = db.Column(db.Integer, db.ForeignKey('entry.id'))
routes.py:
#app.route('/manifests/<manifest_to_view>')
#login_required
def view_manifest(manifest_to_view):
page = request.args.get('page', 1, type=int)
entries = Entry.query.filter_by(manifest=manifest_to_view).paginate(
page, app.config['POSTS_PER_PAGE'], False)
next_url = url_for('view_manifest', manifest_to_view=manifest_to_view, page=entries.next_num) \
if entries.has_next else None
prev_url = url_for('view_manifest', manifest_to_view=manifest_to_view, page=entries.prev_num) \
if entries.has_prev else None
return render_template("view_manifest.html", title='View Manifest', manifest_to_view=manifest_to_view, entries=entries.items, next_url=next_url, prev_url=prev_url)
And from the template:
{% for entry in entries %}
<td>{{ entry.actions.first().location }}</td>
{% endfor %}
This page displays all rows in the Entry table that share a specific "manifest" (an alphanumeric identifier). So you can see my query in routes.py starts:
entries = Entry.query.filter_by(manifest=manifest_to_view)...
For each row from the Entry table, I also need to display the most recent location from the related Action table, but my current line displays the wrong location:
{{ entry.actions.first().location }}
Is there a way to sort locations by the Action.action_date column using order_by() instead of using first()? Or any way to print the most recent location?
Thanks.
found the answer here: SQLAlchemy - order_by on relationship for join table
I just had to change the relationship in model.py
actions = db.relationship('Action', backref='entry', order_by="desc(Action.id)", lazy='dynamic')

How to add comments feature to posts in a flask web application

I am developing a web application with Flask.I am confused how to add comment feature to posts in a web application. Parts of my database models are a give below
class Post(db.Model):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(140))
body = db.Column(db.String(2000))
timestamp = db.Column(db.DateTime)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
comments = db.relationship('Comment', backref='title', lazy='dynamic')
def get_comments(self):
return Comment.query.filter_by(post_id=post.id).order_by(Comment.timestamp.desc())
def __repr__(self):
return '<Post %r>' % (self.body)
class Comment(db.Model):
id = db.Column(db.Integer, primary_key = True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
def __repr__(self):
return '<Post %r>' % (self.body)
And post and comment forms as
class PostForm(Form):
post = StringField('post', validators=[DataRequired()])
title = StringField('title', validators=[DataRequired()])
class CommentForm(Form):
comment = StringField('post', validators=[DataRequired()])
The posts are returned by a function blog_posts() in 'User' model
def blog_posts(self):
return Post.query.order_by(Post.timestamp.desc())
Not sure how to return the comments corresponding to each post. After getting posts my code calls render template(index.html). Then how can I obtain comments and print them?. Please help I am a beginner python developer
Since you've defined the relationship between Post and Comment, you can simply do something like the following in your template:
{% if post.comments %}
{% if post.comments.count() > 0 %}
<h2>Comments</h2>
<p>
{% for comment in post.comments %}
<p>{{ comment.body }}</p>
{% endfor %}
</p>
{% endif %}
{% endif %}

Categories