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
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
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
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_
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')
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 %}