1. Товары относятся к категориями
2. Категории имеют фильтры с возможными значениями
3. Товары имеют атрибуты с теми же возможными значениями
Как переопределить инлайн-поля ManyToManyField в редактировании товара так, чтобы выбор значений атрибута соответствовал набору значений фильтра?
Метод formfield_for_manytomany класса admin.TabularInline где-то вызывается в цикле и получает как аргумент только отдельное поле (db_field) отдельной инлайн-формы.
Мне же для переопределения выборки нужно в этом методе иметь доступ к соседнему полю (filter) инлайн-формы и его набору значений (filter.variant_set).
Как можно пробросить в этот метод значения соседних полей той же инлайн-формы? Какой метод переопределить?
1. models.py (в сокращении)
class Category(MPTTModel): # Категория
name = models.CharField('название', max_length=64)
class Product(models.Model): # Товар
category = TreeForeignKey(Category, models.CASCADE, verbose_name='категория')
def save(self, *args, **kwargs):
# тут кастомная логика с авто-удалением/добавлением атрибутов товарам
class VariantFilter(models.Model): # Фильтр категории
name = models.CharField('имя фильтра', max_length=64)
category = TreeForeignKey(Category, models.CASCADE, verbose_name='категория')
def save(self, *args, **kwargs):
# тут кастомная логика с автодобавлением атрибутов товарам
class Variant(models.Model): # Значения атрибутов товаров
value = models.CharField('значение', max_length=64)
filter = models.ForeignKey(VariantFilter, models.CASCADE)
class VariantAttribute(models.Model): # Атрибут товара
product = models.ForeignKey(Product, models.CASCADE, verbose_name='товар')
filter = models.ForeignKey(VariantFilter, models.CASCADE, verbose_name='атрибут')
values = models.ManyToManyField(Variant, blank=True, verbose_name='значения')
class Meta:
unique_together = (('product', 'filter'),)
2. admin.py (в сокращении)
# Инлайн-поля со значениями фильтров
class VariantInline(admin.TabularInline):
model = Variant
extra = 1
# Редактирование фильтра
@admin.register(VariantFilter)
class VariantFilterAdmin(admin.ModelAdmin):
inlines = [VariantInline]
# Инлайн-поля с атрибутами товаров
class VariantAttributeInline(admin.TabularInline):
model = VariantAttribute
max_num = 0
fields = ('filter', 'values',)
readonly_fields = ('filter',)
def has_delete_permission(self, request, obj=None):
return False
def formfield_for_manytomany(self, db_field, request, **kwargs):
# тут нужно ограничить выбор значений атрибута товара
# для этого сюда НУЖНО ПРОКИНУТЬ соседнее поле filter,
# чтобы достать его набор значений (variant_set)
field = super(VariantAttributeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == 'values':
print(field)
return field
# Редактирование товара
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
model = Product
inlines = [VariantAttributeInline]
Спасибо, что обратили внимание на вопрос.
Буду рад любым предложенным решениям.