Django search returning all objects not the specified ones
I'm currently trying to achieve a search that shows only the ads that contain the text in title, description or tags. It seems like everything should work properly, but the search returns all of the objects.(site has the /?search=foo ending after the button click)
my List View
class AdListView(ListView):
model = Ad
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
favorites = list()
if self.request.user.is_authenticated:
# rows = [{'id': 2}, {'id': 4} ... ] (A list of rows)
rows = self.request.user.favorite_ads.values('id')
# favorites = [2, 4, ...] using list comprehension
favorites = [ row['id'] for row in rows ]
context['favorites'] = favorites
strval = self.request.GET.get("search", False)
if strval:
# Simple title-only search
# __icontains for case-insensitive search
query = Q(title__icontains=strval)
query.add(Q(text__icontains=strval), Q.OR)
query.add(Q(tags__name__in=[strval]), Q.OR)
objects = Ad.objects.filter(query).select_related().distinct().order_by('-updated_at')[:10]
else :
objects = Ad.objects.all().order_by('-updated_at')[:10]
# Augment the post_list
for obj in objects:
obj.natural_updated = naturaltime(obj.updated_at)
context['search'] = strval
return context
part of my template:
<div style="float:right">
<!-- https://www.w3schools.com/howto/howto_css_search_button.asp -->
<form>
<input type="text" placeholder="Search.." name="search"
{% if search %} value="{{ search }}" {% endif %}
>
<button type="submit"><i class="fa fa-search"></i></button>
<a href="{% url 'ads:all' %}"><i class="fa fa-undo"></i></a>
</form>
</div>
{% if ad_list %}
<ul>
{% for ad in ad_list %}
<li>
<a href="{% url 'ads:ad_detail' ad.id %}">{{ ad.title }}</a>
{% if ad.owner == user %}
(<a href="{% url 'ads:ad_update' ad.id %}">Edit</a> |
<a href="{% url 'ads:ad_delete' ad.id %}">Delete</a>)
{% endif %}
{% if user.is_authenticated %}
<!-- Two hrefs with two stacked icons each - one showing and one hidden -->
<a href="#" onclick=
"favPost('{% url 'ads:ad_unfavorite' ad.id %}', {{ ad.id }} );return false;"
{% if ad.id not in favorites %} style="display: none;" {% endif %}
id="favorite_star_{{ad.id}}">
<span class="fa-stack" style="vertical-align: middle;">
<i class="fa fa-star fa-stack-1x" style="color: orange;"></i>
<i class="fa fa-star-o fa-stack-1x"></i>
</span>
</a>
forms.py:
# Create the form class.
class CreateForm(forms.ModelForm):
max_upload_limit = 2 * 1024 * 1024
max_upload_limit_text = naturalsize(max_upload_limit)
# Call this 'picture' so it gets copied from the form to the in-memory model
# It will not be the "bytes", it will be the "InMemoryUploadedFile"
# because we need to pull out things like content_type
picture = forms.FileField(required=False, label='File to Upload <= '+max_upload_limit_text)
upload_field_name = 'ad'
# Hint: this will need to be changed for use in the ads application :)
class Meta:
model = Ad
fields = ['title', 'text', 'picture','price', 'tags'] # Picture is manual
# Validate the size of the picture
def clean(self):
cleaned_data = super().clean()
pic = cleaned_data.get('picture')
if pic is None:
return
if len(pic) > self.max_upload_limit:
self.add_error('picture', "File must be < "+self.max_upload_limit_text+" bytes")
# Convert uploaded File object to a picture
def save(self, commit=True):
instance = super(CreateForm, self).save(commit=False)
# We only need to adjust picture if it is a freshly uploaded file
f = instance.picture # Make a copy
if isinstance(f, InMemoryUploadedFile): # Extract data from the form to the model
bytearr = f.read()
instance.content_type = f.content_type
instance.picture = bytearr # Overwrite with the actual image data
if commit:
instance.save()
self.save_m2m()
return instance