Link to home
Start Free TrialLog in
Avatar of tyrrrr
tyrrrrFlag for Canada

asked on

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

Avatar of tyrrrr
tyrrrr
Flag of Canada image

ASKER

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))
That tells you q_objects is empty. Were you expecting that?
Avatar of tyrrrr

ASKER

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.
ASKER CERTIFIED SOLUTION
Avatar of ramrom
ramrom
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of pepr
pepr

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."
Avatar of tyrrrr

ASKER

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?
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

Avatar of tyrrrr

ASKER

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

Avatar of tyrrrr

ASKER

Thank you! Your insight was very helpful in solving the problem.