Django list matching with if == statement - django

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

Related

Flash message not showing because of conditon

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!

Django get_or_create with icontains

I'm getting an unexpected result using icontains in my get_or_create call.
Take the following example:
>>>team_name = "Bears"
>>>Team.objects.get(name__icontains=team_name) # returns DoesNotExist as expected
>>>team, created = Team.objects.get_or_create(name__icontains=team_name)
>>>print(created) # Prints True as expected
>>>print(team.name) # Prints an empty string!
Why does this create a team with a blank name rather than "Bears"? The reason I'm using get_or_create here is that if a subsequent user posts something like "BearS" I want to get the correct team, not create a duplicate team with incorrect capitalization.
I think here you should split the get() and create() functionalities instead of using get_or_create(), because the __icontains lookup works for get() only.
Try doing something like this:
>>> team_name = 'Bears'
>>> teams = Team.objects.filter(name__icontains=team_name)
# This will filter the teams with this name
>>> team = teams.first() if teams.exists() else Team.objects.create(name=team_name)
# Now your team is the first element of your previous query (it returns a QuerySet with single element) if it exists
# Otherwise, you create a new Team.
Another option besides wencakisa's answer is to include the defaults parameter in get_or_create, because Django strips lookups containing the __ separator. See answers to this question.
The code would be:
Team.objects.get_or_create(
name__icontains=team_name,
defaults = {
"name": team_name
}
)
The right way to do it is using Django's function get_or_create(). But instead of "icontains", you should use "iexact" (), unless you want an exact match, in wich case you should use just "exact":
Team.objects.get_or_create(
name__iexact=team_name,
defaults = {
"name": team_name
}
)
Outside "defaults" you should put your search terms. If the objects doesn't exist, you should write your creation terms inside 'defaults'

Accessing instance attributes that start with a certain string

In my view, I'm trying to blank/delete a number of fields that start with real_.
I can do something like:
plan = get_object_or_404(Plan, pk=self.kwargs['plan_id'])
plan.real_time = None
plan.real_date = None
plan.real_comments = None
plan.real_whatever = None
....
plan.save()
However I guess there must be a way to do this programmatically. All I'd need to do is access the names of the the fields, compare whether it indeed starts with real_ and then update that field.
I'm using get_fields() (as per the documentation). I'm not sure though how to do the last part though.
Following is the code of my view:
plan = get_object_or_404(Plan, pk=self.kwargs['plan_id'])
plan_fields = plan._meta.get_fields()
for field in plan_fields:
if field.name[:5] == "real_":
plan.<not sure what to do here> = None
plan.save()
I guess I must be overlooking something small. Any pointer?
Using Django 1.9.
if field.name[:5] == "real_":
setattr(plan, field.name, None)
Python doc.
I would recommend something nice and neat like this:
plan = get_object_or_404(Plan, pk=self.kwargs['plan_id'])
real_fields = [field for field in plan._meta.get_fields() if field.name.startswith('real_')]
for field in real_fields:
setattr(plan, field, None)
plan.save()
This is partially opinion based, but I feel that the use of the list comprehension and .startswith() are slightly more Pythonic.

Django: How to use django.forms.ModelChoiceField with a Raw SQL query?

I'm trying to render a form with a combo that shows related entities. Therefore I'm using a ModelChoiceField.
This approach works well, until I needed to limit which entities to show. If I use a simple query expression it also works well, but things break if I use a raw SQL query.
So my code that works, sets the queryset to a filter expression.
class ReservationForm(forms.Form):
location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time")
def __init__(self,*args,**kwargs):
city_id = kwargs.pop("city_id") # client is the parameter passed from views.py
super(ReservationForm, self).__init__(*args,**kwargs)
# TODO: move this to a manager
self.fields['location_time_slot'].queryset = LocationTimeSlot.objects.filter(city__id = city_id )
BUT, if I change that to a raw query I start having problems. Code that does not work:
class ReservationForm(forms.Form):
location_time_slot = ModelChoiceField(queryset=LocationTimeSlot.objects.all(), empty_label="Select your prefered time")
def __init__(self,*args,**kwargs):
city_id = kwargs.pop("city_id") # client is the parameter passed from views.py
super(ReservationForm, self).__init__(*args,**kwargs)
# TODO: move this to a manager
query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order'
FROM reservations_locationtimeslot AS ts
INNER JOIN reservations_location AS l ON l.id = ts.location_id
WHERE l.city_id = %s
AND ts.available_reserves > 0
AND ts.datetime_from > datetime() """
time_slots = LocationTimeSlot.objects.raw(query, [city_id])
self.fields['location_time_slot'].queryset = time_slots
The first error I get when trying to render the widget is: 'RawQuerySet' object has no attribute 'all'
I could solve that one thanks to one of the commets in enter link description here, by doing:
time_slots.all = time_slots.__iter__ # Dummy fix to allow default form rendering with raw SQL
But now I'm getting something similar when posting the form:
'RawQuerySet' object has no attribute 'get'
Is there a proper way to prepare a RawQuerySet to be used by ModelChoiceField?
Thanks!
Are you sure you actually need a raw query there? Just looking at that query, I can't see any reason you can't just do it with filter(location__city=city_id, available_reserves__gte=0, datetime_from__gt=datetime.datetime.now()).
Raw query sets are missing a number of methods that are defined on conventional query sets, so just dropping them in place isn't likely to work without writing your own definitions for all those methods.
I temporarily fixed the problem adding the missing methods.
The way I'm currently using the ModelChoiceField I only needed to add the all() and get() methods, but in different scenarios you might need to add some other methods as well. Also this is not a perfect solution because:
1) Defining the get method this way migth produce incorrect results. I think the get() method is used to validate that the selected option is within the options returned by all(). The way I temporarily implemented it only validates that the id exists in the table.
2) I guess the get method is less performant specified this way.
If anyone can think of a better solution, please let me know.
So my temporary solution:
class LocationTimeSlotManager(models.Manager):
def availableSlots(self, city_id):
query = """SELECT ts.id, ts.datetime_to, ts.datetime_from, ts.available_reserves, l.name, l.'order'
FROM reservations_locationtimeslot AS ts
.....
.....
MORE SQL """
time_slots = LocationTimeSlot.objects.raw(query, [city_id])
# Dummy fix to allow default form rendering with raw SQL
time_slots.all = time_slots.__iter__
time_slots.get = LocationTimeSlot.objects.get
return time_slots

Testing a session variable

I came across Django request.session; I know how to set and test it for a specific value.
request.session['name'] = "dummy"
and somewhere I check
if request.session['name'] == "dummy" :
#do something
But, now I have to check whether the session variable was even set in the first place? I mean how can I check whether there exists a value in the request.session['name'] is set?
Is there a way to check it?
Treat it as a Python dictionary:
if 'name' in request.session:
print request.session['name']
How to use sessions: Django documentation: How to use sessions
get will do all the work for you. Check if the key exists, if not then the value is None
if request.session.get('name', None) == "dummy":
print 'name is = dummy'
Another way of doing this is put it in try.
In this the third example code snippet
if you apply del operation in a session variable it which does not exist, so it throws KeyError.
so check it like this.
try:
print(request.session['name'])
except KeyError:
print('name variable is not set')