Answer the question
In order to leave comments, you need to log in
How to override possible ManyToManyField values in InlineModelAdmin given the value of another inline form field?
1. Products belong to categories
2. Categories have filters with possible values
3. Products have attributes with the same possible values
How can I override the inline ManyToManyField fields in product editing so that the selection of attribute values matches the set of filter values?
The formfield_for_manytomany method of the admin.TabularInline class is called somewhere in the loop and receives as an argument only a single field (db_field) of a single inline form.
To override the selection, I need to have access to the neighboring field (filter) of the inline form and its value set (filter.variant_set) in this method.
How can I pass the values of neighboring fields of the same inline form to this method? Which method to override?
1. models.py (abbreviated)
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'),)
# Инлайн-поля со значениями фильтров
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]
Answer the question
In order to leave comments, you need to log in
The field filter
is not editable. I think what you need to access is not the field, but the model object VariantAttribute
. Right?
If so, then this option should suit you: https://stackoverflow.com/a/22003809/1245471 - here they suggest creating a separate class for the form and filtering in it, and then set this class for VariantAttributeInline
(attribute form
, if I don't changes memory).
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question