Reputation: 343
Django 1.8.4 add GenericForeignKey search fields does not work.
I've created several Product models like:
class Product1(models.Model):
...
orders = GenericRelation(Order)
class Product2(models.Model):
...
orders = GenericRelation(Order)
And in Order model:
class Order(models.Model):
content_type = models.ForeignKey(
ContentType,
blank=True,
null=True
)
object_id = models.PositiveIntegerField(
blank=True,
null=True
)
product = generic.GenericForeignKey('content_type','object_id')
This all works Fine,
But when I want to search Produt name in OrderAdmin, I added prodct__name search fields like this:
class OrderAdmin(admin.ModelAdmin):
...
search_fields = [
'product__name',
]
This Does Not Work!
Django raise that:
Field 'product' does not generate an automatic reverse relation and therefore cannot be used for reverse querying.
If it is a GenericForeignKey, consider adding a GenericRelation.
Don't understand How Django 1.8 GenericForeignKey works, GenericRelations Already exist in Products models, but still doesn't work.
Upvotes: 1
Views: 732
Reputation: 343
By override the default get_search_results
method, the following code Generally works, but still got a little problem.
def get_search_results(self, request, queryset, search_term):
"""Override to Include searching `product__name` which is a
GenericForeignKey Field of all product types.
Returns a tuple containing a queryset to implement the search,
and a boolean indicating if the results may contain duplicates.
"""
products = [v for k, v in pro_models.PRODUCT_DICT.iteritems()]
generic_queryset = queryset
product_list = list()
for bit in search_term.split():
for product in products:
product_queryset = product.objects.filter(
Q(name__icontains=bit))
product_list += list(product_queryset)
generic_query = [Q(**{
'content_type': ContentType.objects.get_for_model(product),
'object_id': product.id
}) for product in product_list]
if generic_query:
generic_queryset = generic_queryset.filter(
reduce(operator.or_, generic_query))
else:
generic_queryset = generic_queryset.none()
default_queryset, use_distinct = \
super(OrderAdmin, self).get_search_results(
request,
queryset,
search_term
)
return default_queryset | generic_queryset, use_distinct
Upvotes: 2