Reputation: 89
I am creating an application where food has several components, and each component has a specific value. I want to be able to filter food for the value of a specific component.
Here are my models:
class Food(models.Model):
id = models.AutoField(primary_key=True, db_column="id")
name = models.CharField(max_length=150)
product_type = models.CharField(max_length=150)
class Component(models.Model):
id = models.AutoField(primary_key=True, db_column="id")
name = models.CharField(max_length=150)
value = models.FloatField()
food = models.ForeignKey(Food, related_name='food_components', related_query_name='food_components')
Then I define filter sets and the view
import rest_framework_filters as filters
class ComponentFilter(filters.FilterSet):
name = filters.CharFilter(name="name")
val = filters.NumberFilter(name="value", distinct=True)
minval = filters.NumberFilter(name="value", lookup_type="gte", distinct=True)
maxval = filters.NumberFilter(name="value", lookup_type="lte", distinct=True)
class Meta:
model = Component
class FoodFilter(filters.FilterSet):
name = filters.CharFilter(name='name')
product_type = filters.CharFilter(name='product_type')
components = filters.RelatedFilter(ComponentFilter, name='food_components')
class Meta:
model = Food
class FoodViewSet(viewsets.ModelViewSet):
queryset = Food.objects.all()
serializer_class = FoodSerializer
filter_class = FoodFilter
I want to be able to filter a viewset using more than one field in a related model (combining both parameters). Something like http://whatever/foods/components__name=X&components__value=1 would get me all foods with the element X of value 1. I am using django-rest-framework-filters (https://github.com/philipn/django-rest-framework-filters)
From what I see, since all foods have all the elements, the components__name is irrelevant, and I will get all the foods that have any component with the value 1. How can I combine both?
Thanks in advance!
Upvotes: 3
Views: 1467
Reputation: 24228
You'll need to create a new filter that handles the name
, val
pair on a single Food
object that is related to a given Component
:
class FoodComponentFilter(django_filters.Filter):
def filter(self, qs, value):
strs = value.split(',')
if len(strs) != 2:
raise Exception
return qs.filter(
food_components__in = Component.objects.filter(
name=strs[0],
value=float(strs[1])
)
)
Instantiate this in the FoodFilter
:
class FoodFilter(filters.FilterSet):
component_food_pair = FoodComponentFilter(name='dummy_field')
[...]
class Meta:
model = Food
fields = ('component_food_pair',[...])
Then, use it like:
?component_food_pair=Foo,42.0
Upvotes: 4