Sala
Sala

Reputation: 61

Django haystack SearchQuerySet to QuerySet

I have a very generic view/template to display the contents of a queryset of a given model.
I use from 12 places with 12 different querysets, now I wanted to integrate the haystack search in there but I can't because SearchQuerySet does not match a QuerySet in the template.

With the normal querysets I do

{%for obj in qs%}
    {{obj.foreign_key.name }}
{%endfor%}

With the SearchQuerySet I would need to do

{%for obj in qs%} 
   {{obj.object.foreign_key.name}}
{%endfor%}

Which basically breaks my generic template and view that do now know where the queryset comes from.

I would like a way to have a searchqueryset behave like the normal queryset and I am aware that:

Any hints on how can I keep my template generic but accept SearchQuerySet or convert SearchQuerySet to QuerySet ?

Upvotes: 6

Views: 4559

Answers (4)

Greg
Greg

Reputation: 10352

What about adding a method on your models called object, so that your querysets behave like the SearchQuerySet? Eg

class MyModel(models.Model):
    ...

    @property
    def object(self):
        return self

Upvotes: 4

Kakashi Sensei
Kakashi Sensei

Reputation: 131

For others who came here looking for a more general approach to treating SQS like QS.

I needed something like this for Django Rest Framework so I created the following wrapper for sqs -> qs. It allows the SQS to be processed as if it were a queryset with limited support for iteration and slicing.

You could also invoke load_all before iterating in the generator function.

class SearchQuerySetWrapper(object):
    """
    Decorates a SearchQuerySet object using a generator for efficient iteration
    """
    def __init__(self, qs):
        self.qs = qs

    def count(self):
        return self.qs.count()

    def __iter__(self):
        for result in self.qs:
            yield result.object

    def __getitem__( self, key):
        if isinstance(key, int) and (key >= 0 or key < self.count()):
            # return the object at the specified position
            return self.qs[key].object
        # Pass the slice/range on to the delegate
        return SearchQuerySetWrapper(self.qs[key])

Upvotes: 1

Dimitri Gnidash
Dimitri Gnidash

Reputation: 71

There is a neat generator trick that I used that avoids adding object method to your models, and lets you use the same template for both Django's QuerySet and Haystack SearchQuerySet.

The trick is to wrap your SearchQuerySet into a generator.

# In your view...

def queryset_gen(search_qs):
    for item in search_qs:
        yield item.object  # This is the line that gets the model instance out of the Search object

qs = queryset_gen(sqs)

The advantage of this approach is that it maintains the order in which SearchQuerySet is returned and saves computation and memory as you will not need create or store another instance of the list.

Upvotes: 7

Marco
Marco

Reputation: 335

You can make an array like this:

q = request.GET['q']
    results = SearchQuerySet().auto_query(q)
    obj = []
    for r in results:
        obj.append(r.object)
    return render_to_response('template.html',
        {'obj': obj )

Upvotes: 0

Related Questions