0

I'm using Django-filter, and I would like one of the fields (supervisor) to be a ChoiceFilter where the choices are objects from the model. What's the most efficient way to do that? I tried following this post, but kept getting errors no matter what I changed (currently cannot unpack non-iterable int object).

# models.py
class people(models.Model):
    namelast = models.CharField(max_length=100, verbose_name='Last Name')
    namefirst = models.CharField(max_length=100, verbose_name='First Name')
    supervisor = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL, verbose_name='Supervisor')
    
    def __str__(self):
        return "%s %s" % (self.namefirst, self.namelast)

# filters.py
class office_filter(django_filters.FilterSet):
    supervisor = django_filters.ChoiceFilter(choices=[], lookup_expr='icontains', label='Supervisor')
    # other fields

    class Meta:
        model = people
        fields = ['namelast', 'namefirst', 'supervisor']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        try:
            self.filters['supervisor'].extra['choices'] = [x for x in
                people.objects.all().values_list('supervisor', flat=True).distinct()]
        except (KeyError, AttributeError):
            pass

The goal is to have the supervisor field be a nice menu of all of the people that have been added assigned as a supervisor in the people model.

2 Answers 2

1

I am not a 100% sure, but could you try something?

[people.objects.get(pk=x[0]) for x in people.objects.all().values_list('supervisor', flat=True).distinct()]

or

[people.objects.get(id=x[0]) for x in people.objects.all().values_list('supervisor', flat=True).distinct()]

In the link that you mentioned I believe DatedResource.objects.all().values_list('date', flat=True).distinct()) returns an array of string

In your code people.objects.all().values_list('supervisor', flat=True).distinct() would return a string of int - the IDs of the records as it is a Foreign Key

Sign up to request clarification or add additional context in comments.

2 Comments

That's good to know about what's returned from the link I posted. Unfortunately both versions of your suggestion give the error int object is not subscriptable, so I tried pk=x and got cannot unpack non-iterable people object. That whole line works okay in the shell, so I wonder if it's django-filter not liking whatever list is returned (not clear in error messages).
Oh, I think I figured it out...it has to return a tuple. [(people.objects.get(pk=x).id, people.objects.get(pk=x)) for x in people.objects.all().values_list('supervisor', flat=True).distinct() if x is not None] seems to be working. Thanks for pointing me in the right direction!
1

Ananya's answer helped me get on the correct track of what have that statement return, but after thinking about the errors and how choice lists are usually constructed, I realized I needed it to return a tuple (not just a value). Here is the relevant code that ended up working:

class office_filter(django_filters.FilterSet):
    supervisor = django_filters.ChoiceFilter(choices=[], label='Supervisor')
    #...
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            try:
                self.filters['supervisor'].extra['choices'] = [(people.objects.get(pk=x).id, people.objects.get(pk=x)) for x in people.objects.all().values_list('supervisor', flat=True).distinct() if x is not None]
            except (KeyError, AttributeError):
                pass

The important part being: (people.objects.get(pk=x).id, people.objects.get(pk=x)) rather than just people.objects.get(pk=x).

Also had to remove lookup_expr in the filter field.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.