Creating a Full-Text Search in Flask [closed] - python

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_

Related

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

I want to get the data from the sqlalchemy table in html using jinja2 format {{all.{{item}}}} where item is the element of string and all is data

in my code "all" is the data taken from the sqalchemy database,now i am having another list "asked", In that list,name are of columns are stored of which details are required
but when i run this code it give me an error:
asked = ["S_NO", "FAIL_TIME", "RIGHT_TIME", "FAILURE_REMARKS"],
when i run "all.S_NO" or "all["S_NO"]" it run's perfect. but the case I defined it gives me error
enter code here
{% for all in data %}
{% for item in asked: %}
<tr>
<td>{{all.{{item}}}}</td>
{% endfor %}
flask code
class Data(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=True)
S_NO = db.Column(db.String(250) ,nullable=False, unique= True)
STN_CODE = db.Column(db.String(250), nullable=False)
STN_NAME = db.Column(db.String(250), nullable=False)
ADSTE = db.Column(db.String(250), nullable=False)
SSE= db.Column(db.String(250), nullable=False)
ROUTE=db.Column(db.String(250),nullable=False)
SEC=db.Column(db.String(250), nullable=False)
DIV=db.Column(db.String(250), nullable=False)
FAIL_TIME=db.Column(db.String(250), nullable=False)
RIGHT_TIME=db.Column(db.String(250), nullable=False)
DURATION=db.Column(db.String(250), nullable=False)
FAILURE_REMARKS=db.Column(db.String(1000), nullable=False)
NAME_OF_GEAR_FAILED=db.Column(db.String(250), nullable=False)
TYPE_OF_MAIN_GEAR_FAILED =db.Column(db.String(250), nullable=False)
Failed_Gear_Desc=db.Column(db.String(250),nullable=False)
DEPTT=db.Column(db.String(250), nullable=False)
Cause=db.Column(db.String(250), nullable=False)
Train_Detention=db.Column(db.String(250), nullable=False)
def __repr__(self):
return f"< S_NO ={self.S_NO}, STN_CODE={self.STN_CODE},STN_NAME = {self.STN_NAME}, ADSTE ={self.ADSTE},SSE= {self.SSE}, ROUTE={self.ROUTE},SEC= {self.SEC}, DIV= {self.DIV},FAIL_TIME= {self.FAIL_TIME},RIGHT_TIME= {self.RIGHT_TIME},DURATION= {self.DURATION},FAILURE_REMARKS= {self.FAILURE_REMARKS}, NAME_OF_GEAR_FAILED= {self.NAME_OF_GEAR_FAILED}, TYPE_OF_MAIN_GEAR_FAILED = {self.TYPE_OF_MAIN_GEAR_FAILED}, Failed_Gear_Desc={ self.Failed_Gear_Desc}, DEPTT={ self.DEPTT}, Cause={ self.Cause},Train_Detention= {self.Train_Detention}>"
#app.route("/")
def home():
new_data = db.session.query(Data).all()
demand = ["S_NO", "FAIL_TIME", "RIGHT_TIME", "FAILURE_REMARKS"]
return render_template("index.html", data = new_data,header = failure_event, asked =demand)
new data look
< S_NO =2, STN_CODE=JHI,STN_NAME = Jind, ADSTE =ROK,SSE= SSE/SIG/JHI, ROUTE=D,SEC= DLI(EX) - BTI(EX), DIV= DLI,FAIL_TIME= 5/19/21 3:20,RIGHT_TIME= 5/19/21 5:55,DURATION= 2:35:00,FAILURE_REMARKS= YELLOW ASPECT LED UNIT WAS DEFECTIVE , SAME REPLACED AT 04:15. LONG DURATION DUE TO NO TEST MARGIN AVAILABLE. LDM-04/05/21, LDI-08/05/21. OLD LED MAKE - SARNARTI INC. , NAME_OF_GEAR_FAILED= UP STR. SIGNAL S-43 FAILED FOR LINE NO. 7, TYPE_OF_MAIN_GEAR_FAILED = SIGNAL, Failed_Gear_Desc=MACLS, DEPTT=SNT, Cause=LED DEF,Train_Detention= LOAD=15">
type of data is
<class 'list'>
error is defined below
{{all.{{item}}}}
jinja2.exceptions.TemplateSyntaxError: expected name or number
I tried my best to make my problem understandable, if I failed please let me know so that I can try again, It's my first time on StackOverflow
It is always better to do complex logic part in flask itself rather than in template.
Use this to get the values of database and to pass it to template:
#app.route("/")
def home():
new_data = db.session.query(Data).all()
demand = ["S_NO", "FAIL_TIME", "RIGHT_TIME", "FAILURE_REMARKS"]
all_data_item = []
for data in new_data:
for item in demand:
if item in data:
all_data_item.append(data.item)
return render_template("index.html", data = all_data_item,header = failure_event, asked =demand)
In template:
{% for d in data %}
<td>{{d}}</td>
{% endfor %}
instead of using the def repr(self):
get the result in the form of dict
class Data(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=True)
S_NO = db.Column(db.String(250) ,nullable=False, unique= True)
STN_CODE = db.Column(db.String(250), nullable=False)
STN_NAME = db.Column(db.String(250), nullable=False)
ADSTE = db.Column(db.String(250), nullable=False)
SSE= db.Column(db.String(250), nullable=False)
ROUTE=db.Column(db.String(250),nullable=False)
SEC=db.Column(db.String(250), nullable=False)
DIV=db.Column(db.String(250), nullable=False)
FAIL_TIME=db.Column(db.String(250), nullable=False)
RIGHT_TIME=db.Column(db.String(250), nullable=False)
DURATION=db.Column(db.String(250), nullable=False)
FAILURE_REMARKS=db.Column(db.String(1000), nullable=False)
NAME_OF_GEAR_FAILED=db.Column(db.String(250), nullable=False)
TYPE_OF_MAIN_GEAR_FAILED =db.Column(db.String(250), nullable=False)
Failed_Gear_Desc=db.Column(db.String(250),nullable=False)
DEPTT=db.Column(db.String(250), nullable=False)
Cause=db.Column(db.String(250), nullable=False)
Train_Detention=db.Column(db.String(250), nullable=False)
def dobule_to_dict(self):
result = {}
for key in self.__mapper__.c.keys():
if getattr(self, key) is not None:
result[key] = str(getattr(self, key))
else:
result[key] = getattr(self, key)
return result
outside the class use the below function
def to_json(all_vendors):
v = [ ven.dobule_to_dict() for ven in all_vendors ]
return v
users = Data.query.all()
sheet_data = to_json(users)

'list' object has no attribute 'id'

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 %}

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