Django admin filter for inline model rows

82 Views Asked by At

I have a parent model (Author) & inline models (Book)


class Author(models.Model):
    age = models.IntegerField()

class Book(models.Model):
    name = models.CharField(max_length=250)
    price = models.CharField(max_length=250)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

Book model has 3 rows

to convey my issue I'm giving UI results in readable dict format

{id:1, name:'book1', price: 50, author_id: 1}
{id:2, name:'book2', price: 75, author_id: 1}
{id:3, name:'book1', price: 65, author_id: 2}

in admin.py, i have AuthorAdmin that has a list filter,

list_filter = ['age', 'book__name', 'book__price']

in django admin list view page, if i filter /admin/?book__name=book1&book__price=75

it gives Author(id=1), Author(id=2) as result

but it should only return the id:1 row alone.

kindly help how to use list_filter in m2m relations (inlines) in django admin.

i have used __ to filter the inlines, but the results are not accurate.

my understanding is that django is returning the parent if atleast 1 of the inline item matches the query. i want the filters to be chained.

1

There are 1 best solutions below

0
YellowShark On

I tried to replicate your issue and was not able to do so. In fact, it seems to work exactly as you are expecting it to. I am using Django 3.2.21 and Python 3.9.7. I created a new Django app called stack77067914 within an existing project of mine. I then created the following files:

$ tree ./stack77067914/
stack77067914/
|-- __init__.py
|-- admin.py
|-- fixtures
|   `-- stack77067914.json
|-- migrations
|   |-- 0001_initial.py
|   `-- __init__.py
`-- models.py
# stack77067914.__init__.py
# empty file
# stack77067914.admin.py
from django.contrib import admin

from .models import Author, Book


@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    list_filter = ['age', 'book__name', 'book__price']


@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    pass
[
  {
    "THIS_FILE_NAME": "stack77067914.json",
    "model": "stack77067914.Author",
    "pk": 1,
    "fields": {
      "age": 25
    }
  },
  {
    "model": "stack77067914.Author",
    "pk": 2,
    "fields": {
      "age": 66
    }
  },
  {
    "model": "stack77067914.Book",
    "pk": 1,
    "fields": {
      "name": "book1",
      "price": 50,
      "author": 1
    }
  },
  {
    "model": "stack77067914.Book",
    "pk": 2,
    "fields": {
      "name": "book2",
      "price": 75,
      "author": 1
    }
  },
  {
    "model": "stack77067914.Book",
    "pk": 3,
    "fields": {
      "name": "book1",
      "price": 65,
      "author": 2
    }
  }
]
# stack77067914.migrations.__init__.py
# empty file
# stack77067914.migrations.0001_initial.py
# Generated by Django 3.2.21 on 2023-09-12 11:28

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Author',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
                ('age', models.IntegerField()),
            ],
        ),
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)),
                ('name', models.CharField(max_length=250)),
                ('price', models.CharField(max_length=250)),
                ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stack77067914.author')),
            ],
        ),
    ]
# stack77067914.models.py
from django.db import models


class Author(models.Model):
    age = models.IntegerField()


class Book(models.Model):
    name = models.CharField(max_length=250)
    price = models.CharField(max_length=250)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

Obviously I ran ./manage.py migrate stack77067914 followed by ./manage.py loaddata stack77067914, and then I visited the admin page and used the filters as you described.

When I visit the url /admin/stack77067914/author/?book__name=book1&book__price=75, I am only shown the first Author with ID #1, which is exactly what you're expecting - the filters should be combined in an "AND" fashion, rather than "OR". So I'm not sure what issue you're experiencing here, but maybe check your own code against what I've shared here and perhaps there's a typo or something else that you're missing.

I'm glad to answer any follow-up questions of course. Good luck!