Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filter foreignkey field in django admin

Tags:

python

django

I have these models:

class Entity(models.Model):
       name=models.CharField(max_length=100)
      
class Theme(models.Model):
   name=models.CharField(max_length=100)
   entity=models.OneToOneField(Entity)

class Company(models.Model):
    name=models.CharField(max_length=100)
    theme=models.OneToOneField(Theme,null=True,blank=True)

I want to filter the theme field when adding a Company in the admin, something like this:

class CompanyAdmin(admin.ModelAdmin):
   def queryset(self, request):
      qs = super(CompanyAdmin, self).queryset(request)
      qs.theme.queryset = Theme.objects.filter(name__iexact='company')
      return qs
      
admin.site.register(Company, CompanyAdmin)

I've tried many things, but nothing worked! How can I do this?

like image 969
Asma Gheisari Avatar asked Apr 16 '12 17:04

Asma Gheisari


People also ask

What does ForeignKey mean in Django?

ForeignKey is a Django ORM field-to-column mapping for creating and working with relationships between tables in relational databases.

Can you filter by property Django?

Nope. Django filters operate at the database level, generating SQL. To filter based on Python properties, you have to load the object into Python to evaluate the property--and at that point, you've already done all the work to load it.


5 Answers

Use the render_change_form method:

class CompanyAdmin(admin.ModelAdmin):
    def render_change_form(self, request, context, *args, **kwargs):
         context['adminform'].form.fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
         return super(CompanyAdmin, self).render_change_form(request, context, *args, **kwargs)
like image 53
BenH Avatar answered Oct 05 '22 19:10

BenH


I actually prefer to do it in get_form like so:

Django < 2:

class CompanyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(CompanyAdmin, self).get_form(request, obj, **kwargs)
        form.fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
        return form

Django >= 2

class CompanyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(CompanyAdmin, self).get_form(request, obj, **kwargs)
        form.base_fields['theme'].queryset = Theme.objects.filter(name__iexact='company')
        return form
like image 30
Moritz Avatar answered Oct 05 '22 20:10

Moritz


look here http://books.agiliq.com/projects/django-admin-cookbook/en/latest/filter_fk_dropdown.html

@admin.register(Hero)
class HeroAdmin(admin.ModelAdmin, ExportCsvMixin):
    ...
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "category":
            kwargs["queryset"] = Category.objects.filter(name__in=['God', 'Demi God'])
        return super().formfield_for_foreignkey(db_field, request, **kwargs)
like image 37
slavugan Avatar answered Oct 05 '22 20:10

slavugan


In Django 3 it is easy :

class CompanyAdmin(admin.ModelAdmin):
    list_display = ('name','theme')
    list_filter = ('theme__name',)

admin.site.register(Company,CompanyAdmin)

This will show you a filter on the right of your screen with the list of your theme's name.

like image 37
G.Lebret Avatar answered Oct 05 '22 19:10

G.Lebret


Another option is to create a custom model form where the queryset attribute of the theme field will be fine tuned to meet your needs.

class CompanyForm(ModelForm):
    class Meta:
        model = CompanyForm
        fields = __all__ # or a tuple of fields

    def __init__(self, *args, **kwargs):
        super(CompanyForm, self).__init__(*args, **kwargs)
        if self.instance: # Editing and existing instance
            self.fields['theme'].queryset = Theme.objects.filter(name__iexact='company')

This model form can be also reused outside of the django admin area.

like image 45
Raiyan Avatar answered Oct 05 '22 20:10

Raiyan