How to filter choices in Django2's autocomplete_fields? How to filter choices in Django2's autocomplete_fields? python python

How to filter choices in Django2's autocomplete_fields?


If you are using autocomplete_fields for a ManyToManyField on 'self',this example will exclude the current object.

Get the current object's id by overriding get_form:

field_for_autocomplete = Nonedef get_form(self, request, obj=None, **kwargs):    if obj:        self.field_for_autocomplete = obj.pk    return super(MyAdmin, self).get_form(request, obj, **kwargs)

Next, override get_search_results. Modify the queryset only for your model's autocomplete URI:

def get_search_results(self, request, queryset, search_term):    queryset, use_distinct = super().get_search_results(request, queryset, search_term)    # Exclude only for autocomplete    if request.path == '/admin/myapp/mymodel/autocomplete/':        queryset = queryset.exclude(field=self.field_for_autocomplete)    return queryset, use_distinct


Override the ModelAdmin's get_search_results method to use the query you want. You can see in the get_queryset method for the view providing the data for autocomplete fields that it's used to get the queryset - the source as of this answer is https://github.com/django/django/blob/03dbdfd9bbbbd0b0172aad648c6bbe3f39541137/django/contrib/admin/views/autocomplete.py#L42.


I had somehow the same problem, when using autocomplete_fields the limit_choices_to was not taking affect, and then I found a solution for my case which may help others too.this an idea and a solution for my case, anybody should change the code for his/her use.

imagine we have two models model_A and modle_B:we are going to override the "get_search_results" of
model-admin of model_A(because model_B has a foreign_key(or m2m) to it)in my case I just want to limit choices to all model_A objects which
currentlly dont have a model_B connected object(s)or in case of updating an object of model_B limit to just the previous model_A object(s).so we go

# moodels.pyclass model_A(models.Model):    name = models.CharField()class model_B(models.Model):    name = models.CharField()    fk_field = models.OneToOneField( #ManyToManyField or ForeignKey    model_A,    related_name='fk_reverse',    on_delete=models.CASCADE)# admin.pyclass model_A_Admin(admin.ModelAdmin):   search_fields = ('name', ) def get_search_results(self, request, queryset, search_term):        import re        queryset, use_distinct = super().get_search_results(request, queryset, search_term)    # note: str(request.META.get('HTTP_REFERER')) is the url from which the request had come/previous url.        if "model_b/add/" in str(request.META.get('HTTP_REFERER')):        # if we were in creating new model_B instanse page        # note: the url is somehow containing model_Bs calss name then / then "add"        # so there is no related object(of model_A) for non exsisting object(of model_B)            queryset = self.model.objects.filter(fk_reverse=None)        elif re.search(r"model_b/\d/change/", str(request.META.get('HTTP_REFERER'))):        # if we were in updatineg page of an exsisting model_B instanse        # the calling page url contains the id of the model_B instanse        # we are extracting the id and use it for limitaion proccess            pk = int(re.findall(r'\d+', str(str(request.META.get('HTTP_REFERER')).split('/')[-3: ]))[-1])            queryset = self.model.objects.filter(fk_reverse=pk)        return queryset, use_distinct

https://gist.github.com/mh-firouzjaah/48dceae592d4b4275fa31d37ac77ff69