Search code examples
djangodjango-filter

Call a function to update queryset on django-filter Choicefielter


I have a working function that populates a dropdown with the emails of all registered tutors. The problem is that when a new Tutor is registered, it gets redirected to the home template (where the form filter is rendered), but the dropdown with the choices is not updated, even if I hit refresh. It gets updated after in VisualStudio I stop the server and run again runserver, or press ctrl + s and the server is reloaded. I figured out that the function get_tutores() is only called once, and what I want to achieve is to call that function from the views every time the page is reloaded.

MODEL

class Tutor(models.Model):
 
    user = models.OneToOneField(
        User, on_delete=models.CASCADE, primary_key=True)
    nombre = models.CharField(max_length=50, blank=False, null=True)
    apellido = models.CharField(max_length=50, blank=False, null=True)
    biografia = models.TextField()
    curriculum = models.FileField(upload_to="curriculums/", blank=True, null=True)
    foto = models.ImageField(blank=True, null=True)
    carrera = models.ManyToManyField(Carrera, blank=True)
    linea_invest = models.ManyToManyField(Linea_Invest, blank=True)
    correo = models.EmailField(blank=True, null=True)
    numero_celular = models.CharField(max_length=20, blank=True, null=True)
 
    class Meta:
        verbose_name_plural = "Tutores"
        verbose_name = "Tutor"
 
    def __str__(self):
        return '%s %s' % (self.nombre, self.apellido)

FILTER:

def get_tutores():
    tutores = []
    for tut in Tutor.objects.all():
        tutores.append((tut.user.id,tut.user.email,))
    return tutores
 
 
 
class TutorFilter(django_filters.FilterSet):
    nombre = CharFilter(field_name="nombre", label="Nombre",lookup_expr='icontains')
    apellido = CharFilter(field_name="apellido", label="Apellido",lookup_expr='icontains')
    carrera = ModelMultipleChoiceFilter(field_name= "carrera", queryset= Carrera.objects.all())
    user = ChoiceFilter( label = "correo", choices=get_tutores())
    
    
    class Meta:
        model = Tutor
        fields = ("nombre", "apellido", "carrera","user")

VIEWS

def home(request):
    tutores = Tutor.objects.all()
    filtro_tutor = TutorFilter(request.GET, queryset=tutores)
    tutores = filtro_tutor.qs
    
    context = {
        'tutores':  tutores , 'filtro_tutor': filtro_tutor
    }

    return render(request, 'home.html', context)

TEMPLATE

<section class="section">
                <div class="container">
                <div class="columns  ">
                    <div class="column  ">
                        <div class="field is-grouped is-small ">
                            <div class="control ">
                                  <form  method="get">
                                    {{  filtro_tutor.form }}
                                    
                                    <div class="control">
                                      <button class="button is-link" type="submit">
                                        Buscar
                                      </button>
                                    </div>
                             </div>
                           </form>
                           
                        </div>
                        <div>
                          {% for obj in filtro_tutor.qs %}
                          {{ obj.correo }} - ${{ obj.user }}<br />
                          {% endfor %}
                        </div>
                        
                    </div>
                  </div>
                </div>
             </section>

I printed in the template the queryset in the for loop and there it shows me the new email form the new tutor that I added (test9@g.com), but it doesn't display in the Dropdown.

Tryed to do this in the home view:

filtro_tutor['user'].extra['choices'] = get_tutores()

But got "TutorFilter' object is not subscriptable"


Solution

  • It looks like your user = ChoiceFilter(…) is in essence a ModelMultipleChoiceFilter, but where you specify a different field_class that uses the email of the user, and a queryset that filters the users by Tutor:

    from django import forms
    
    class UserModelChoiceField(forms.ModelChoiceField):
        
        def label_from_instance(self, obj):
            return str(obj.email)
    
    class UserModelMultipleChoiceFilter(ModelMultipleChoiceFilter):
        field_class = UserModelChoiceField
    
    class TutorFilter(django_filters.FilterSet):
        # …
        user = UserModelMultipleChoiceFilter(
            queryset=User.objects.filter(tutor__isnull=False)
        )