Flash message not showing because of conditon - flask

In flask, im trying to flash a message when there are no results from the user's search. Problem is, the flash is not doing its job. I believe its because of the if condition but im not sure why.
If i make this the condition: if counter == 0: then flash , it works. But even when the user is just reloading the search page, the message gets flashed so its not desirable. That why im trying to create the condition based on book.query & this is where im stuck.
#app.route("/search", methods=['GET', 'POST'])
def search():
keyword = escape(request.form.get("keyword"))
books = Book.query.filter(or_(Book.isbn.like(f'%{keyword}%'), Book.title.like(
f'%{keyword}%'), Book.author.like(f'%{keyword}%'))).all()
counter = Book.query.filter(or_(Book.isbn.like(f'%{keyword}%'), Book.title.like(
f'%{keyword}%'), Book.author.like(f'%{keyword}%'))).count()
if books is None:
flash('No matches found!', 'info')
return render_template('search.html', title='Search', books=books)

In your query for books you use .all() at the end.
.all() returns a list - in case of no result, this will be an empty list, but you compare the result to None.
While both None and [] are falsy values, they are not identical.
But you explicitly compare object identity with the is keyword.
So you could change your if guard to
if not books:
or
if len(books) == 0:
Make sure to tell us how it worked out!

Related

Flask session cookie reverting

I am sure I am probably being stupid but struggling to wrap my head around this one.
I have a flask website and I am setting up a checkout page for it so users can add their items to the cart etc. Everything was going great, I was able to add items to the cart, get a total etc (using sessions) however when I have tried to implement the ability for users to update the cart on the checkout page, when my form posts, the session data only survives the initial load. The print statement shows the data I am collecting is fine, and the session cookie is set initially, as everything updates, however the moment I then change page, it reverts to whatever it was before I made the update.
#views.route("/shopping-cart", methods=['GET','POST'])
def to_cart():
clear_cart = 'views.to_clear_cart'
if 'shopping' in session:
shopping_list = session['shopping']
sum_list = []
for quantity, price in shopping_list.values():
sum_list.append(quantity * price)
total = sum(sum_list)
if request.method == "POST":
new_quantity = int(request.form.get('quantity'))
product_id = request.form.get('issue')
unit_price = int(request.form.get('price'))
print(new_quantity, product_id, unit_price)
shopping_list[f'{product_id}'] = [new_quantity, unit_price]
return redirect(url_for('views.to_cart'))
return render_template("cart.html",
shopping_list=shopping_list,
total=total,
clear_cart=clear_cart,
)
else:
return render_template("cart.html",
clear_cart=clear_cart
)
I just do not really understand why it is not updating as from what I can tell, the code is running fine, and it does update, but then the session cookie just reverts itself to whatever it was before (using browser side cookies for this for testing).
Any help appreciated!!
After much confusion as everything seemed to be working absolutely fine after I rewrote this in about 5 different ways and printed half the app in the console, I finally found the answer and it is indeed me being an idiot.
It turns out if you modify a value in place rather than creating or deleting it does not automatically save the session state and you just need to state explicitly that it has been modified.
Turns out the answer was as simple as this line of code.
session.modified = True

Django list matching with if == statement

I'm hoping this is super simple. I just started playing around with Django for fun and have been playing around with making a search engine.
I'm setting a temporary list in a views.py file so I set it like this:
tempsearch_list = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
Later in my code I want to see if it's the same as I originally set so I'm trying to do this:
if tempsearch_list == 'Name Not Found':
This never matches. Even if I put it as the next statement after I set it. What am I doing wrong here. This has to be super simple. I've been trying different things for more time than I'd like to admit.
you filtered the objects as tempsearch_list = Name.objects.filter(Q(name__iexact='Name Not Found')) and later on you when you want to compare if tempsearch_list equals to Name Not Found, you don't need any if statment just use if tempsearch_list.exists().
tempsearch_list.exists() will return True if there was an object named Name Not Found else it returns False
how do I check the query set is still equal to the original way it was set
The queryset(tempsearch_list) won't changed unless you reassign it, and that would be always update in case of adding, editing or removing a Name. but again if you wondering, you can compare it with fresh queryset as if tempsearch_list == Name.objects.filter(Q(name__iexact='Name Not Found'))
Ok, so I appreciate everyone who responded. I think this helped a lot. Here's what I did for now. There's probably a better way to do this but it works
tempsearch_queryset1 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
tempsearch_queryset2 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
if set(tempsearch_queryset1) == set(tempsearch_queryset2):
Note. Without the set commands it does not work. This doesn't work:
tempsearch_queryset1 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
tempsearch_queryset2 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
if tempsearch_queryset1 == tempsearch_queryset2:
Your problem is compare Queryset and string (Queryset is list of model so you can access model by index and access model field by . like model.name
you can do that like
for tempsearch in tempsearch_list :
if tempsearch.name == "Name Not Found":
You should compare Charfield like name field with string

Django - How to tertermine content_type in if statement?

I want to find out what content_type I'm about in my function but I'm Unable to reach the "got me" print statement no matter how I design my if statement. I also tried to use pprint to get the naming of the content_type but with no effect till now.
def mark_refunded(modeladmin, request, queryset):
queryset.update(status=2)
transactions = queryset.all()
for transaction in queryset.all():
print(transaction)
transaction.sender.acc_usd_balance += float(transaction.amount)
transaction.sender.save()
transaction.receiver.acc_usd_balance -= float(transaction.amount)
transaction.receiver.save()
print(transaction.content_type)
if transaction.content_type == "App | Sell Type A":
print("got me")
It seems that I'm unable to compare the output of print(transaction.content_type) with the if statement, why that?
I would expect that the output is the same value that I ask for at the if statement.
Assuming content_type is a foreign key, you'd need to compare if str(...) == ....
However, the more important issue here is that multiple concurrent requests will eventually absolutely surely corrupt those account balances since you're not managing them in an atomic way.

Object is not legal as a SQL literal value

Long time reader, first time poster, please be gentle.
I've been working on a web app using Flask and SQLAlchemy that allows users to review and comment on MMA fights. I have a list of fights in a SQL table appropriately named "fights" and I'm trying to use dynamic routing to filter through the data. I have a list of all the fights on one route like so:
#app.route('/ufc251')
#login_required
def ufc251():
return render_template('ufc251.html', fights=Fight.query.all())
which helped me make a slick page with all the fights listed, and then made another route for info on individual fights like so:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html')
so far, so good. If I click on a fight from the main page i get sent to a url fightsite/fights/<fight_id>, which is perfect. The problem that I'm having is that I can't for the life of me figure out how to call the data from the row for a single fight. If i change my route to:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id).first())
I get the error
sqlalchemy.exc.ArgumentError: Object <Fight 1> is not legal as a SQL literal value
but if i give id a value (i.e. id=1) it will display the data from the first row in my fights table, so i feel like the problem is in the (id=id) part, but after hours of scouring the internet, I can't seem to find a solution.
Any help would be greatly appreciated. And yes, I've read the other StackOverflow article on this subject, however the answer doesn't seem to apply to this situation.
Thank you in advance!
I figured it out, however I decided I'd leave the question in case anybody else has this issue.
i changed:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id).first())
to:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id.id).first())
because initially it was passing the argument 'fight_1' instead of just '1'. I hope nobody else has to spend this long trying to solve the same problem!
The use of id to hold a Fight confuses things. Then there's the double query when one would suffice.
Consider changing
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id).first())
to
fight = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=fight)

end point to accept multiple values, including query strings

I have a view which should accept an end point with a query parameter, as well as without a parameter.
http://localhost:8001/v1/subjects?owner_ids=62,144
and
http://localhost:8001/v1/subjects
Here's my view file...
class SubjectPagination(JsonApiPageNumberPagination):
"""
Required for frontend to retrieve full list.
"""
max_page_size = 5000
class SubjectViewSet(Subject.get_viewset()):
pagination_class = SubjectPagination
def get_queryset(self):
import pdb; pdb.set_trace()
queryset = Subject.objects.all()
if self.request.GET['owner_ids']:
owner_id_list = self.request.GET['owner_ids'].split(',')
owner_id_list_integer = []
for i in owner_id_list:
owner_id_list_integer.append(int(i))
return queryset.filter(organization__in=owner_id_list_integer)
else:
return queryset
SubjectUserRoleViewSet = Subject.get_by_user_role_viewset(
SubjectViewSet, GroupRoleMap, Role)
I am trying to figure out how to handle both the end points? Please advice what needs to be done at the view to handle a URI with or without query strings?
Here's the urls.py
router.register(r'subjects', views.SubjectViewSet)
First of all, is a good practice to send the parameters in url-form-encode, avoiding things like that, in this case for send a list you could send id as:
?owner_ids[]=62&owner_ids[]=144
the querydict its going to be like this :
<QueryDict: {'owner_ids[]': ['62', '144']}>
and you could process it easily, like this
self.request.GET.getlist('owner_ids[]', [])
remember to use the get and get list functions of the request method GET and POST, to avoid dict errors.
Second, split returns a list the for statement in owner list id is totally unnecessary, and the queryset statement __in accept array of strings, if you actually want to convert all the items to integers use list comprehensions. For example, to convert all the items in a list to integer, just have to use:
owner_ids = [int(i) for i in owner_ids ]
this is way more fast in python and way more pythonic, and also cool too see.
and last, all urls should finish in /, even django has a settings for that called append_slash
this is what i can tell about the ambiguous question you are asking, in the next times please write questions more precisely that help people help you.