Search code examples
djangoselectdjango-filter

Access to related model field in django_filters


I'm constructing Django-based 4-language website for a real estate agency. I'm using django-filter package to filter my objects (real estate properties) by certain parameters, such as type (house, apartment, etc.), city and some others.

My 'type' field is a foreign key for the model 'Type'. It uses ModelChoiceFilter to select all available types from the database, and redner them as a select element with options, which is and is displayed as a drop list with options, which is good so far.

class SalePropertyFilter(FilterSet):
    ...

    type = ModelChoiceFilter(
        queryset=Type.objects.all(),
        empty_label=_("Any type"),
        label="",
        widget=forms.Select(attrs={'class': 'form-control'}),
        )

But for some reason the options are displayed as slug names of the types ('house', 'apartment', etc., see the attached picture). It is the 'slug' field of my foreign key model Type. Instead of this, I want to print 'name' field in the options. This field is translated (django-modeltranslation package), so that in English version one should see options 'House', 'Apartment'..., and in Spanish version - 'Casa', 'Apartamento', etc.

I tried modify this field in my PropertyFilter as using '__' symbol (type__name instead of type), but it doesn't seem to work.

Please, help me, I'm stuck!

enter image description here


Solution

  • The problem consisted of two parts: 1) select options are displayed as slug names, 2) the field labels are not translated.

    The first problem was caused by my silly error. The method "str" returned self.slug, which was wrong. It was solved my rewriting this method:

    def __str__(self):
        return f"{self.name}"
    

    For the second problem I didn't find a proper solution. The form is generated by the RangeFilter, which is called by PropertyFilter with and, in theory, should get context from is (from the queryset which is passed as a parameter). Instead of this, this RangeFilter is initialized when I start the server (runserver), without the context, without the queryset, with default language ('en'). When I open the "Properties list" web page, this filter is initialized second time, this time with the context (query and language), but, for some reason, the form is rendered by first instance of the filter. I cannot understand, why it happens.

    The solution, which I found, is not very good, but it works. I suppressed field labels in my RangeFilter, and render the form manually.

    <form method="GET" action="{% url 'properties:list' %}">
        <div id="div_id_city" class="mb-3"> 
            {{ propertyform.city }}
        </div>
        <div id="div_id_type" class="mb-3"> 
            {{ propertyform.type }}
        </div>
        <div id="div_id_price" class="mb-3">
        <p>{% translate "Price, €" %}</p>
            {{ propertyform.price }}
        </div>
        <div class="form-group mb-0">
            <button class="search-button">{% translate "Search" %}</button>
        </div>
    </form>
    

    In this form, I display translated labels manually (<p>{% translate "Price, €" %}</p>). In the choice fields, the labels are not necessary, since in my PropertyFilter, which is context-aware, I set placeholders, which are translated: self.filters['type'].field.empty_label = _("Any type").

    In result, the entire filter form on the page displays translated (see picture). However, I still would like to know the proper solution for this issue, so, if anyone knows the more nice solution for the problem, let me know, please.

    enter image description here