Errors When Using TabularInline in admin page

The Logic here is:
we have three models Catalog, Category, and Product
the product have an attributes with ForeignKeys for both Catalog and Category.
on Admin page while using TabularInline, it gives this Error

Error:

SystemCheckError: System check identified some issues:

ERRORS:
<class 'Products.admin.CatalogInlineAdmin'>: (admin.E202) 'Products.Catalog' has no ForeignKey to 'Products.Product'.
<class 'Products.admin.CategoryInlineAdmin'>: (admin.E202) 'Products.Category' has no ForeignKey to 'Products.Product'.

Admin.py:

# Django Imports.
from django.contrib import admin
# Custom Imports.
from Products.models import Catalog, Category, Product, ProductImage


class CatalogInlineAdmin(admin.TabularInline):
    model = Catalog


class CategoryInlineAdmin(admin.TabularInline):
    model = Category


class ProductImageInlineAdmin(admin.TabularInline):
    model = ProductImage


@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    class Meta:
        model = Product

    list_display = ['name', 'catalog', 'category', 'sku', 'available', 'diminssion', 'age', 'inventory',
                    'price', 'tag']
    search_fields = ['name', 'catalog', 'category', 'sku', 'tag']
    filter_horizontal = ()
    list_filter = []
    fieldsets = ()
    ordering = ['catalog', 'category', 'name', ]
    prepopulated_fields = {'slug': ('name', 'sku')}
    inlines = [CatalogInlineAdmin, CategoryInlineAdmin, ProductImageInlineAdmin]

Models.py:

# Django Imports.
from django.db import models
from django.urls import reverse_lazy
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
# Third Party Imports.
import pathlib

class Catalog(models.Model):
    CatalogChoices = (
        ('toys', 'Educational Wooden Toys'),
        ('Aratoys', 'Arabic Educational Wooden Toys'),
        ('mont', 'Montessori Materials'),
        ('furn', 'Pre-School Furniture'),
    )
    name = models.CharField(verbose_name=_('Catalog Name'), choices=CatalogChoices, max_length=255)
    available = models.BooleanField(verbose_name=_('Catalog Availability'), default=True)

    def __str__(self):
        return f'{self.name}'


class Category(models.Model):
    name = models.CharField(verbose_name=_('Category Name'), max_length=255, unique=True)
    parent = models.ForeignKey('self', verbose_name=_('Category Parent'), on_delete=models.RESTRICT)

    def __str__(self):
        return f'{self.name}'


class Product(models.Model):
    catalog = models.ForeignKey(Catalog, verbose_name='Product Catalog', on_delete=models.CASCADE)
    category = models.ForeignKey(Category, verbose_name='Product Category', on_delete=models.CASCADE)
    name = models.CharField(verbose_name=_('Product Name'), max_length=255)
    sku = models.IntegerField(verbose_name=_('Product SKU'))

    def __str__(self):
        return f'{self.name} - {self.sku}'

A TabularInline is used to show the “Many” side of a OneToMany relationship. However, since it’s Product that has the FK to both Catalog and Category, it is the “Many” side. There is only one Catalog and one Category related to an individual product, so it makes no sense to use an Inline for them.

1 Like

I used the related name to solve this.


@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    class Meta:
        model = Product

    list_display = ['name', 'product_catalog', 'product_category', 'sku', 'available', 'diminssion', 'age', 'inventory',
                    'price', 'tag']
    search_fields = ['name', 'product_catalog', 'product_category', 'sku', 'tag']
    filter_horizontal = ()
    list_filter = []
    fieldsets = ()
    ordering = ['product_catalog', 'product_category', 'name', ]
    prepopulated_fields = {'slug': ('name', 'sku')}
    inlines = [CatalogInlineAdmin, CategoryInlineAdmin, ProductImageInlineAdmin]

edited the models to:

class Catalog(models.Model):
    CatalogChoices = (
        ('toys', 'Educational Wooden Toys'),
        ('Aratoys', 'Arabic Educational Wooden Toys'),
        ('mont', 'Montessori Materials'),
        ('furn', 'Pre-School Furniture'),
    )
    name = models.CharField(verbose_name=_('Catalog Name'), choices=CatalogChoices, max_length=255)
    product = models.ForeignKey('Product', verbose_name=_('Product'), related_name=_('product_category'),
                                on_delete=models.CASCADE)
    available = models.BooleanField(verbose_name=_('Catalog Availability'), default=True)

    def __str__(self):
        return f'{self.name}'


class Category(models.Model):
    name = models.CharField(verbose_name=_('Category Name'), max_length=255, unique=True)
    parent = models.ForeignKey('self', verbose_name=_('Category Parent'), on_delete=models.RESTRICT)
    product = models.ForeignKey('Product', verbose_name=_('Product'), related_name=_('product_category'),
                                on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.name}'


class Product(models.Model):
    name = models.CharField(verbose_name=_('Product Name'), max_length=255)
    sku = models.IntegerField(verbose_name=_('Product SKU'))

    def __str__(self):
        return f'{self.name} - {self.sku}'

thanks ken
i edit it so i can add more than category for one product.