Access filter choice's fields

I have problem with integration my filter system.

Suppose that we have a model Country which has a name and icon

And we have a Team model which has a ForeignKey to Country.

We have a filterset_class generated with Django-filter.

class TeamFilter(django_filters.FilterSet):
    country = django_filters.ModelMultipleChoiceFilter(queryset=Country.objects.all(),
    widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-control'}))

    class Meta:
        model = Team
        fields = ['country']

When I try to integrate filter system to front-end, It shows the filter options and It filters the teams but It is not possible to access Country object fields like ‘icon’.

However, I have to show the icon for each country.

<form action="" method="get">
      <div class="primary-dropdown__inner-list">
        {% for country in filter.form.country %}
        <div class="checkbox-item">
          <div class="checkbox-item__inner">
            <div class="checkbox-item__inner-checkmark">
              <img src="images/icon/check-ic.svg" alt="">
            </div>
            <div class="checkbox-item__inner-label">
              <img src="{{ country.icon }}" alt="">
              <span>{{ country }}</span>
            </div>
          </div>
        </div>
        {% endfor %}
      </div>
      <button type="submit">Uygula</button>
    </form>

    {% for team in filter.qs %}
      <ul>
        <li><a href="{{ team.get_absolute_url }}">{{ team.name }}</a></li>
      </ul>
    {% endfor %}

How can I enhance what I need properly?

Thanks in advance.

What does your Country object look like? Specifically, what is the icon member of that class? Is it a CharField? FileField?

Hi @tragicomic.

Can I suggest you look at the Iterating relationship choices docs. It show how you can override create_option() in order to customise the select generation. (If that’s not sufficient the underlying iterator and iterator value classes are also exposed.) You should be able to access your Country in order to add additional HTML attributes (or elements) as you need.

Hi,

Icon is an ImageField.

Country is as follows,

class Country(models.Model):
    name = models.CharField(max_length=254)
    icon = models.ImageField(upload_to='images/country')
    ...

I want to create the filter form like this.Screenshot from 2021-05-03 10-02-53

Thank you for interest.

Thank you.
I will review it and try to apply it to my code.
I’ll share the result here.

When you want to render an ImageField, you need to render the url attribute of that field, not the field itself.

How exactly you do this may be different depending upon whether these are static files or media files.

Since you have an upload_to attribute in that model, I’ll assume for the moment that these are media files. You can then render it as:
<img src="{{ country.icon.url }}" alt="">

Hi, @KenWhitesell and @carltongibson

I’m trying to design my code with your approach.

I try to make use of Iterating relationship choices doc to acces Country icons.

It looks like I was not successful.

class CountrySelect(forms.Select):
    def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
        option = super().create_option(name, value, label, selected, index, subindex, attrs)
        if value:
            option['attrs']['data-icon'] = value.instance.icon.url
        return option


class TeamFilter(django_filters.FilterSet):
    country = django_filters.ModelMultipleChoiceFilter(queryset=Country.objects.all(),
    widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-control'}))

    class Meta:
        model = Team
        fields = ['country']
        widgets = {'country': CountrySelect}

Am I too far from the solution or not, I wonder it.

Thanks.

Can you be more specific about the results you’re getting? What does the HTML being rendered look like?

Sure,

While the teams.html’s form section is like this,

<form action="" method="get">
  <div class="primary-dropdown__inner-list">
    {% for country in filter.form.country %}
    <div class="checkbox-item">
      <div class="checkbox-item__inner">
        <div class="checkbox-item__inner-checkmark">
          <img src="images/icon/check-ic.svg" alt="">
        </div>
        <div class="checkbox-item__inner-label">
          <img src="{{ country.icon.url }}" alt="">
          <span>{{ country }}</span>
        </div>
      </div>
    </div>
    {% endfor %}
  </div>
  <button type="submit">Uygula</button>
</form>

It renders form elements like so,

<form action="" method="get">
  <div class="primary-dropdown__inner-list">
    
    <div class="checkbox-item">
      <div class="checkbox-item__inner">
        <div class="checkbox-item__inner-checkmark">
          <img src="images/icon/check-ic.svg" alt="">
        </div>
        <div class="checkbox-item__inner-label">
          <img src="" alt="">
          <span><label for="id_country_0"><input type="checkbox" name="country" value="3" class="form-control" id="id_country_0">
 Canada</label></span>
        </div>
      </div>
    </div>
    
...

While teams.html’s form section like this,

<form action="" method="get">
    {{ filter.form.country }}
    <input type="submit" />
</form>

It renders,

<form action="" method="get">
    <ul id="id_country" class="form-control">
<li><label for="id_country_0"><input type="checkbox" name="country" value="3" class="form-control" id="id_country_0">
 Canada</label>

...
</ul>
    <input type="submit" />
</form>

It looks like country here would be a FormField and not an instance of Country. This means that country.icon wouldn’t be the right reference.

I’m not familiar with the django_filters library, so I’m not familiar with how it stores its data - you’ll need to figure out how to get access to the actual Country instance.

@carltongibson is Maintainer of Django Filter.

He suggested to take a look at iterating relationship choices docs

I’ve been reviewing django-filter doc for a while, I think I couldn’t find what I was looking for.

maybe he can guide me again.

Meanwhile, I will continue to search.

Thanks.