Reputation: 640
I'm trying to turn my django-filter fields into dropdowns.
class UserFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['category', 'genre', 'instrument', ]
def filter(request):
filter = UserFilter(request.GET, queryset=Product.objects.all())
return render(request, 'filter.html', {'filter': filter})
I'm trying to achieve this by using ModelChoiceFilter, like this:
category=django_filters.ModelChoiceFilter(queryset=Product.objects.all())
genre = django_filters.ModelChoiceFilter(queryset=Product.objects.all())
instrument=django_filters.ModelChoiceFilter(queryset=Product.objects.all)))
It works! However instead of returning the desire column, it returns title
filed on all of the django-form fields. That is coming from my model.
def __str__(self):
return self.title
The same behavior can be observed when working with simple Django model forms. In this case I'm just overriding label_from_instance
function of the ModelChoiceField
class like this:
class CategoryModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return obj.category
My question is how to override ModelChoiceFilter
? Or probably there is another convenient way to achieve dropdowns with django-filter?
UPDATE
As djnago-filter is coming with dropdowns for ForeignKeys by default, I just changed my model. Now it looks like so:
class Category(models.Model):
category = models.CharField(max_length=50, blank=True)
class Genre(models.Model):
genre = models.CharField(max_length=50, blank=True)
class Instrument(models.Model):
instrument = models.CharField(max_length=50, blank=True)
class Product(models.Model):
category = models.ForeignKey(Category)
genre = models.ForeignKey(Genre)
instrument = models.ForeignKey(Instrument)
title = models.TextField(max_length=200, blank=True)
def __str__(self):
return self.title
Now it changed it's behavior. It nows the number of the objects but not the actual strings. Like this:
Category object - Genre object - Instrument object - title1
Category object - Genre object - Instrument object - title2
Category object - Genre object - Instrument object - title3
The dropdowns itself are working fine without any intervention:
class UserFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['category', 'genre', 'instrument', ]
Upvotes: 1
Views: 12368
Reputation: 141
I've used the same solution, but sometimes fully normalizing the model is something I want to avoid. Maybe I've missed it, but I'm surprised django_filters.modelChoiceFilter won't simply return any attribute in the queryset, not just foreign key names.
Here's another solution that generates the choices dynamically from the queryset.
class DynamicChoiceMixin(object):
@property
def field(self):
queryset = self.parent.queryset
field = super(DynamicChoiceMixin, self).field
choices = list()
have = list()
# iterate through the queryset and pull out the values for the field name
for item in queryset:
name = getattr(item, self.field_name)
if name in have:
continue
have.append(name)
choices.append((name, name))
field.choices.choices = choices
return field
class DynamicChoiceFilter(DynamicChoiceMixin, django_filters.ChoiceFilter):
pass
class UserFilter(django_filters.FilterSet):
category = DynamicChoiceFilter(name=‘category’)
genre = DynamicChoiceFilter(name=‘genre’)
instrument = DynamicChoiceFilter(name=‘instrument’)
class Meta:
model = Product
fields = ['category', 'genre', 'instrument', ]
Upvotes: 0
Reputation: 640
I finally made it work. This is the working model:
class Category(models.Model):
category = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.category
class Genre(models.Model):
genre = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.genre
class Instrument(models.Model):
instrument = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.instrument
class Product(models.Model):
category = models.ForeignKey(Category)
genre = models.ForeignKey(Genre)
instrument = models.ForeignKey(Instrument)
title = models.TextField(max_length=200, blank=True)
def __str__(self):
return self.title
Upvotes: 1