Пытаюсь изобрести серебряную пулю, которую потом можно будет использовать в других проектах. Дошел вот до чего.
models.py
class ListKeyProperty(models.Model):
"""
Реестр свойств
"""
name = models.CharField(verbose_name='Название', max_length=64)
uom = models.CharField(verbose_name='единица измерения', max_length=16, blank=True, null=True,)
class Meta:
verbose_name = 'Ключ параметров'
verbose_name_plural = 'Ключи параметров'
def __str__(self):
return self.name
class ListPropertyValues(models.Model):
"""
Реестр значений свойств
"""
value = models.CharField(verbose_name='Значение', max_length=128)
key_property = models.ForeignKey(ListKeyProperty, verbose_name='связан со свойством')
class Meta:
verbose_name = 'Значение параметров'
verbose_name_plural = 'Значения параметров'
def __str__(self):
return '%s - %s' % (self.key_property.name, self.value)
class Categories(models.Model):
"""
Категории изделий
"""
...
available_properties = models.ManyToManyField(ListKeyProperty, verbose_name='Доступные свойства', blank=True)
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'Категории'
ordering = ('order',)
def __str__(self):
return '%s' % (self.name)
class Product(models.Model):
"""
Модель продукта
"""
...
category = models.ForeignKey(Categories, verbose_name='Принадлежит категории')
...
class Meta:
verbose_name = 'Продукт'
verbose_name_plural = 'Продукты'
ordering = ('name',)
def __str__(self):
return '%s' % (self.name)
"""
если у объекта есть propety, ключи которых не присутствуют в category,
например, если мы поменяли категорию, то эти proprty удаляем т.к их не
должно быть у изделия в данной категории.
После чего проверяем, все ли связанные с category свойства есть у этого продукта,
если нет, то создаем их с путыми значениями
"""
def save(self):
if (self.marge_fix==None):
self.marge_fix = 0
self.total_price = self.base_price+self.marge_fix
super(Product, self).save()
for key_property_category in self.category.available_properties.all():
check_cat_prop_in_product = False
for item_property_product in self.property_product.all():
if not item_property_product.key in self.category.available_properties.all():
item_property_product.delete()
if key_property_category == item_property_product.key:
check_cat_prop_in_product = True
if check_cat_prop_in_product == False:
new_item_property = Property(key=key_property_category, product=self)
new_item_property.save()
class Property(models.Model):
"""
Свойства, связанные с изделием. Используется либо value, либо диапазон value - second_value,
либо предустановленные значения из списка preset_value. Value и second_value используются, если
нужно добавить значение в свободной форме. preset_value используется, если по этим полям будет фильтрация или выборка.
"""
key = models.ForeignKey(ListKeyProperty, verbose_name='Название')
value = models.CharField(verbose_name='Значение', max_length=128, blank=True, null=True,)
second_value = models.CharField(verbose_name='Второе значение(диапазон)', max_length=128, blank=True, null=True,)
preset_value= models.ForeignKey(ListPropertyValues, verbose_name=u'фиксированные свойства', blank=True, null=True, related_name=u'list_property_value')
product = models.ForeignKey(Product, verbose_name=u'связан с моделью', blank=True, null=True, related_name=u'property_product')
class Meta:
verbose_name = 'Свойство'
verbose_name_plural = 'Свойства'
def __str__(self):
return self.key.name
файл admin.py
class PropertyInline(admin.TabularInline):
fields = ('value','second_value','preset_value',)
model = Property
extra = 0
can_delete = False
max_num = 1
class ProductAdmin(admin.ModelAdmin):
....
inlines = [ImageProductInline, PropertyInline]
Все выглядит очень красиво, не смог победить только одну проблему.
Необходимо, что бы в инлайновых полях PropertyInline, в выпадающем списке preset_value были только значения из ListPropertyValues связанные с ListKeyProperty.
Нашел один рецет, там это решают через change_veiw()
class ProductAdmin(admin.ModelAdmin):
inlines = [ImageProductInline, PropertyInline]
....
def change_view(self, request, object_id, extra_context=None):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'preset_value':
object_property = Property.objects.get(id = object_id)
kwargs['queryset'] = ListPropertyValues.objects.filter(key_property__id = object_property.key.id)
return super(PropertyInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
PropertyInline.formfield_for_foreignkey = formfield_for_foreignkey
self.inline_instances = [PropertyInline(self.model, self.admin_site)]
return super(ProductAdmin, self).change_view(request, object_id, extra_context=extra_context)
Тут результат оказался не совсем тот, для каждого инлан объекта должен быть свой сосбвенный набор ListPropertyValues в зависимости от ListKeyProperty, а у меня значения во все инлайны подставляются одинаковые, которые доступны для первого инлайна.