Django ecommerce product db design

Я разработал базу данных для моего проекта django ecommerce, но у него есть некоторые проблемы, цель этой разработки является иметь продукты с различными характеристиками, например, мобильный телефон имеет свои собственные свойства и телевизор тоже, это мой models.py:

'''

And admin.py:

'''

    from django.contrib import admin
    from django.http import HttpResponseRedirect
    from mptt.admin import MPTTModelAdmin
    from .models import *
    from .forms import ProductSpecForm


    @admin.register(Category)
    class CategoryAdmin(MPTTModelAdmin):
        readonly_fields = ('slug',)


    class SpecificationInline(admin.TabularInline):
        model = ProductSpecifications
        extra = 2


    @admin.register(ProductType)
    class ProductTypeAdmin(admin.ModelAdmin):
        inlines = (SpecificationInline,)


    class SpecificationValueInline(admin.TabularInline):
        model = ProductSpecificationValue
    # form = ProductSpecForm
    # fields = ('specification', 'value')
    # readonly_fields = ('specification',)
    # 
    # def has_add_permission(self, request, obj):
    #     return False
    # 
    # def has_delete_permission(self, request, obj=None):
    #     return False


    @admin.register(Product)
    class ProductAdmin(admin.ModelAdmin):
        inlines = (SpecificationValueInline,)
        readonly_fields = ('slug',)

        # def response_post_save_add(self, request, obj):
        #     return HttpResponseRedirect(
        #         reverse("admin:%s_%s_change" % (self.model._meta.app_label, 
        #         self.model._meta.model_name), args=(obj.id,)))

'''
проблема в том, что в панели администратора продукта, когда вы хотите добавить или изменить продукт, я хочу, чтобы поле выбора спецификации в форме SpecificationValueInline показывало мне только спецификации, связанные с типом продукта, а не все спецификации в db, строки, которые я закомментировал в admin.py с некоторыми сигналами и формой, были моим подходом к решению этой проблемы, но я не знаю, был ли он лучшим, помогите мне, пожалуйста! signals.py:

'''

from django.dispatch import receiver
    from django.db.models.signals import pre_save, post_save
    from .models import Category, Product, ProductSpecificationValue, ProductSpecifications


    @receiver(pre_save, sender=Product)
    @receiver(pre_save, sender=Category)
    def initialize_slug(sender, instance, *args, **kwargs):
        if (not instance.slug) or (instance.tracker.has_changed('name')):
            instance.slug = instance.name.replace(' ', '_')


    @receiver(post_save, sender=Product)
    def initialize_specifications(sender, instance, created, **kwargs):
        if created:
            product_type = instance.product_type
            for specification in product_type.specifications.all():
                ProductSpecificationValue.objects.create(product=instance, 
                specification=specification)
        elif instance.tracker.has_changed('product_type'):
            ProductSpecificationValue.objects.filter(product=instance).delete()
            product_type = instance.product_type
            for specification in product_type.specifications.all():
                ProductSpecificationValue.objects.create(product=instance, 
                specification=specification)



    @receiver(post_save, sender=ProductSpecifications)
    def add_new_specs_to_related_products(sender, instance, created, **kwargs):
        if created:
            product_type = instance.product_type
            for product in product_type.products.all():
                ProductSpecificationValue.objects.create(specification=instance, 
                product=product)

''' forms.py: '''

from django import forms
    from django.forms import ModelChoiceField

    from .models import ProductSpecificationValue, Product


    class ProductSpecForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            if hasattr(self.instance, 'product'):
                self.fields['specification'] = ModelChoiceField(
                    queryset=self.instance.product.product_type.specifications.all())

        class Meta:
            model = ProductSpecificationValue
            fields = ('specification', 'value')

'''

вы можете использовать formfield_for_foreignkey в SpecificationValueInline

class SpecificationValueInline(admin.TabularInline):
    model = ProductSpecificationValue

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "specification":
            product_id = request.resolver_match.kwargs.get('object_id')
            productType = Product.objects.get(id = product_id).product_type
            kwargs["queryset"] = ProductSpecification.objects.filter(product_type=productType)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

mohsen ma answer was usefull I made some changes and it got better but I still doubt it is enough or best practice, if user changes the product type he/she should stay on change page to fill the specification idk how: '''

@receiver(post_save, sender=Product)
def sync_specs_with_type(sender, instance, created, **kwargs):
    if created or instance.tracker.has_changed('product_type'):
        if not created:
            instance.specifications.all().delete()
        for spec in instance.product_type.specifications.all():
            ProductSpecificationValue.objects.create(product=instance, specification=spec)

class SpecificationValueInline(admin.TabularInline):
    model = ProductSpecificationValue
    extra = 0

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        product_id = request.resolver_match.kwargs.get('object_id')
        if product_id and db_field.name == "specification":
            product_type = Product.objects.get(id=product_id).product_type
            kwargs["queryset"] = ProductSpecifications.objects.filter(product_type=product_type)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)


@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    readonly_fields = ('slug',)
    inlines = (SpecificationValueInline,)

    def response_post_save_add(self, request, obj):
        messages.add_message(request, messages.INFO, 'set you product specifications')
        return HttpResponseRedirect(
            reverse("admin:%s_%s_change" % (self.model._meta.app_label, self.model._meta.model_name), args=(obj.id,)))

    def get_inlines(self, request, obj):
        if obj:
            return super().get_inlines(request, obj)
        return ()

'''

Вернуться на верх