Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2319
  • Last Modified:

django, python :: reduce() of empty sequence with no initial value

Hi
I am trying to add a search view to an application I wrote in django but my EntryManager() seems to be getting hung up on the last line of code when django tries to call the url of the search.

This EntryManager() (models.py) is excellent for performing searches in the django shell ($ python manage.py shell) like

x = Entry.objects.search('spam')
list(x)

for example

However when I attempt to visit the url of the search I am met with the error " reduce() of empty sequence with no initial value " and a reference to the last line of EntryManager()

return qs.filter(reduce(operator.or_, q_objects))
I use this method to strip multiple word queries and place underscores between the words

type error:
reduce() of empty sequence with no initial value

The problems seems to be that the EntryManager() requires a string from the beginning and I haven't been able to make it work without one.

The rest of my code works perfectly.

Obviously the value will be empty before a query is made. What am I doing wrong? Is there perhaps a better way to connect my search view to this object?

//////////////////////
models.py
 
import operator
from django.db import models
from django.db.models import Q
 
class EntryManager(models.Manager):
        def search(self, search_terms):
                terms = [term.strip() for term in search_terms.split()]
                q_objects = []
                for term in terms:
                        q_objects.append(Q(name__icontains=term))
                        q_objects.append(Q(description__icontains=term))
                qs = self.get_query_set()
                return qs.filter(reduce(operator.or_, q_objects))
 
//////////////////////
views.py
 
def searching(request):
       query_string = ''
       if ('q' in request.GET) and request.GET['q'].strip():
               query_string = request.GET['q'].strip()
       results = Entry.objects.search(query_string)
       return render_to_response("search_results.html", {'query_string': query_string, 'results' : results})
 
//////////////////////
search_results.html
 
<div>Searched Results</div>
 
{%if results%}
{% for e in results%}
<a href=../{{e.slug}}>{{e.name}}</a></div>
{% endfor %}
{% else %} Nothing to see here...
{% endif %}
 
//////////////////////

Open in new window

0
tyrrrr
Asked:
tyrrrr
  • 5
  • 2
  • 2
1 Solution
 
tyrrrrAuthor Commented:
this is the error:

reduce() of empty sequence with no initial value
This is the error:

Request Method:         GET
Request URL:    http://dsfffffffffffffffffffff/search/
Exception Type:         TypeError
Exception Value:        reduce() of empty sequence with no initial value
Exception Location:     /dsfffffffffffffffffffff/models.py in search, line 59

views.py in searching
  68. results = Entry.objects.search(query_string)

models.py in search
  59. return qs.filter(reduce(operator.or_, q_objects))
0
 
ramromconsultant Commented:
That tells you q_objects is empty. Were you expecting that?
0
 
tyrrrrAuthor Commented:
I know that it will be empty before a query is made but I am unsure how to circumvent the reduce() object in the case that there is no q.

I have been advised to simply return qs.all() or qs.none() instead of qs.filter() in this case but I am not exactly sure how to implement this.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
ramromconsultant Commented:

        def search(self, search_terms):
                terms = [term.strip() for term in search_terms.split()]
                if terms:
                        q_objects = []
                        for term in terms:
                                q_objects.append(Q(name__icontains=term))
                                q_objects.append(Q(description__icontains=term))
                        qs = self.get_query_set()
                        return qs.filter(reduce(operator.or_, q_objects))
                return qs.all() # or qs.none as desired

Open in new window

0
 
peprCommented:
Have a look at http://docs.python.org/library/functions.html#reduce

If you do not know what is inside the sequence, you can also get the empty sequence. Use the third argument of the reduce(). The doc says

"If the optional initializer is present, it is placed before the items of the
 iterable in the calculation, and serves as a default when the iterable
 is empty."
0
 
tyrrrrAuthor Commented:
The initializer has to be an integer though. How can this be used in the case of something that is being used to reduce unicode strings?
0
 
peprCommented:
The documentation shows only the example. The initializer could be of any type that is expected by the function passed to reduce. Try the separate Python sample below. If you remove the u'' initializer (empty unicode string) from the bottom line, you get the following error:

Traceback (most recent call last):
  File "C:\tmp\___python\tyrrrr\a.py", line 13, in <module>
    result = reduce(greater, lst)
TypeError: reduce() of empty sequence with no initial value

If you put the initializer there, the result will contain the empty string (or whatever string that you put as the initializer).
def greater(a, b):
    if a > b:
        return a
    else:
        return b
 
lst = [ u'aaa', u'bbb', u'ccc']
result = reduce(greater, lst)
print result
 
lst = []
result = reduce(greater, lst, u'')
print result

Open in new window

0
 
tyrrrrAuthor Commented:
This is the final solution. Note that qs must be defined before it is referenced.
Thanks everyone!
class EntryManager(models.Manager):
	def search(self, search_terms):
		terms = [term.strip() for term in search_terms.split()]
		qs = Entry.objects.all()
		if terms:
			q_objects = []
			for term in terms:
				q_objects.append(Q(name__icontains=term))
                                q_objects.append(Q(description__icontains=term))
	        	qs = self.get_query_set()
	        	return qs.filter(reduce(operator.or_, q_objects))
	        return qs.none() #or qs.all() as the case may be

Open in new window

0
 
tyrrrrAuthor Commented:
Thank you! Your insight was very helpful in solving the problem.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 5
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now