Stack Overflow на русском Asked by Wild_boyzz on November 10, 2021
Ломаю голову над задачей, но понимаю, что не могу решить сам.
Описание проблемы:
Допустим есть некий интернет-магазин со следующими моделями: ‘Category’, ‘Subcategory’, ‘Basis’, ‘Property’, ‘Product’.
Как можно заметить в модели Basis добавлена связь с моделью property – M2M, так мы получаем нужные характеристики для группы продуктов, вместо того, чтобы выбирать характеристики для продукта по отдельности.
Вопрос:
На данный момент мы имеем Basis который группе продуктов присваивает одни и те же характеристики* – модель Property. Но если выбирать значения* (поле data модели Property) в модели Property, то значения соответственно дублируются собственно как и сами характеристики для каждого товара.
(*небольшой пример в терминологии: Характеристики- "ширина": Значения – "100";)
Как присвоить значения для характеристик? Чтобы каждый Product находящийся в своем Basis имел одинаковые характеристики, которые в свою очередь имели разные значения относительно продукта.
Кратко о методах которыми пытался реализовать:
Пробовал использовать Django EAV, фреймворк Contenttypes, JsonField.
Перелопатил много вопросов в гугле, касающихся реализации характеристик, конкретики не нашел. Пересмотрел множество вопросов касающихся данных методов. Из этого всего самое толковое, что нашел это, и то мне не помогло. Все равно не понимаю как в своей задаче это реализовать.
Уверен, что решение кроется в правильной реализации этих методов, но я не смог точно ни с одним разобраться. Подозреваю, что Data должна быть отдельной моделью, но не приходит в голову как ее связать с Product и все тут.
Если так и есть подскажите пожалуйста, как правильно и толково будет это сделать, у меня уже мозг замылился и к решению прийти не могу долго. Спасибо.
#models/product.py
class Category(models.Model):
""" Category of products """
name = models.CharField('Название категории', max_length=250)
alias = models.CharField('Алиас', max_length=200, db_index=True)
slug = models.SlugField(max_length=50, unique=True)
icon_field = models.ImageField('Изображение', blank=True, null=True, upload_to='category_icon/')
...
class Subcategory(models.Model):
""" Subcategory of products """
name = models.CharField('Название подкатегории', max_length=250)
alias = models.CharField('Алиас', max_length=200, db_index=True)
slug = models.SlugField(max_length=50, unique=True)
categories = models.ForeignKey(Category, verbose_name='Категория', on_delete=models.SET_NULL, null=True)
icon_field = models.ImageField('Изображение', blank=True, null=True, upload_to='subcategory_icon/')
...
class Property(models.Model):
""" Properties of products, tec-info """
name = models.CharField('Свойство', max_length=200, db_index=True, unique=True)
alias = models.CharField('Алиас', max_length=200, db_index=True)
data = models.CharField(max_length=200, verbose_name='Значение')
slug = models.SlugField(max_length=50, unique=True, db_index=True)
...
class Basis(models.Model):
"""
Basis (of products which have same tec info and properties, as group of same products in Basis)
That decision easy to use*, than get property separate to each product. In this decision you can
get the list of properties to basis and this list of properties will be displayed in group of
products which is includet to Basis object.
Also this decisions uses to large markets which have big nomenclature, and different association
with naming of categories
*Easy to use - is when you assign some properties to group of products, instead assign properties
to every product
"""
name = models.CharField('Название основы', max_length=250)
alias = models.CharField('Алиас', max_length=200, db_index=True)
slug = models.SlugField(max_length=50, unique=True)
subcategories = models.ForeignKey(Subcategory, verbose_name='', on_delete=models.SET_NULL, null=True)
properties = models.ManyToManyField(Property, verbose_name='Свойство', related_name='property')
icon_field = models.ImageField('Изображение', blank=True, null=True, upload_to='basis_icon/')
...
class Product(models.Model):
""" Products in catalogue """
name = models.CharField('Название продукта', max_length=250, db_index=True)
brand = models.ForeignKey(
Brand,
verbose_name='Бренд',
on_delete=models.SET_NULL,
null=True,
related_name='brands'
)
collection = models.ForeignKey(
Collection,
verbose_name='Коллекция',
on_delete=models.SET_NULL,
null=True,
related_name='collections'
)
article = models.CharField('Артикул', max_length=250, db_index=True)
slug = models.SlugField(max_length=50, unique=True, db_index=True)
description = models.TextField('Описание')
price = models.DecimalField('Цена', max_digits=10, decimal_places=2)
available = models.BooleanField('Наличие товара', default=True)
created = models.DateTimeField('Дата и время создания товара', auto_now_add=True)
updated = models.DateTimeField('Дата и время последнего изменения', auto_now_add=True)
title_img = models.ImageField('Изображение', upload_to='products/')
categories = models.ForeignKey(
Category,
verbose_name='Категория',
on_delete=models.SET_NULL,
null=True,
related_name='categorys'
)
subcategories = models.ForeignKey(
Subcategory,
verbose_name='Подкатегория',
on_delete=models.SET_NULL,
null=True,
related_name='subcategorys'
)
basis = models.ForeignKey(
Basis,
verbose_name='Основа',
on_delete=models.SET_NULL,
null=True,
related_name='basises'
)
...
В коде все лишнее, не относящееся к вопросу поудолял, чтобы не отвлекало от вопроса
Вы пытаетесь сделать классическую Entity-Attribute-Value модель (плюс мелкие добавления типа категорий, которые существенно не влияют на проблему, с которой вы столкнулись).
Проблема у вас возникла, потому, что вы не разделили Attribute
и Value
. Они у вас сейчас представлены в одной таблице Property
. И идея, что Data должна быть отдельной моделью
- это оно и есть, а именно выделение Value
в отдельную джанго модель.
Для наглядности я переименовал джанго модели.
ProductType
- это аналог Basis
. Он описывает тип продукта, т.е. по сути какие у продукта данного типа могут быть характеристики. Собственно список возможных характеристик - это PropertyType
(описывает тип характеристики и к какому ProductType
она пренадлежит).
Для каждого типа продукта можно создать конкретные экземпляры. Они хранятся как ProductInstance
(у вас это Product
). У каждого экземпляра продукта есть конкретные значения характеристик. Они хранятся как PropertyInstance
(возможно PropertyValue
или ProductInstancePropertyValue
будет более подходящим или понятным названием). Ну и каждый PropertyInstance
содержит собственно значение характеристик конкретного продукта и ссылку на PropertyType
, который описывает тип хранящегося значения.
Пример
ProductType (тип продукта)
--+------
id|name
--+------------
1 | мобильный телефон
2 | ноутбук
ProductInstance (конкретный продукт)
--+-----------------+-----------------
id| product_type_id |name
--+-----------------+---------------
1 | 1 | iphone 10
2 | 1 | samsung galaxy S5
3 | 2 | macbook pro 15
4 | 2 | dell xps 13
PropertyType (тип характеристики)
--+-----------------+-------------------------+------
id| product_type_id |name | type
--+-----------------+-------------------------+------
1 | 1 | операционная система | string
2 | 1 | поддержка bluetooth | boolean
3 | 2 | диагональ экрана | integer
4 | 2 | вес | decimal
PropertyInstance (значение характеристики конкретного продукта)
--+---------------------+-------------------+------
id| product_instance_id | property_type_id | value
--+---------------------+-------------------+------
1 | 1 | 1 | IOS 13
2 | 1 | 2 | true
3 | 2 | 1 | Android 7
4 | 2 | 2 | true
5 | 3 | 3 | 15
6 | 3 | 4 | 2.5
7 | 4 | 3 | 13
8 | 4 | 4 | 1.6
Я к названиям добавил Type
и Instance
чтобы в четче разделить где тип, а где экземпляр, в этом объяснении.
А вообще, возможно, ProductType
, Product
, Property
и Value
окажутся более практичными названиями.
Answered by Roman Konoval on November 10, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP