Django. Как создать два внешних ключа в модели Товара- для названия каталога и его слага
возникла проблема с созданием и работой внешних ключей. Код models.py
from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from django.contrib.auth.models import User
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(Q(status='в наличии') | Q(status='под заказ') | Q(status='нет в наличии'))
class Goods(models.Model):
STATUS_CHOICES = (
('ожидается', 'Ожидается'),
('в наличии', 'В наличии'),
('под заказ', 'Под заказ'),
('нет в наличии', 'Нет в наличии'),
)
goods_name = models.CharField(max_length = 70, verbose_name='Имя товара')
goods_info = models.TextField(blank = True, verbose_name='Описание товара')
manufacturer = models.TextField(blank = True, verbose_name='Производитель товара')
product_care = models.TextField(blank = True, verbose_name='Уход')
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='eco_goods', verbose_name = 'Администратор')
goods_image = models.ImageField(upload_to = 'images/goods/%Y/%m', verbose_name = 'Изображение товара')
product_code = models.CharField(max_length = 15, verbose_name='Код товара')
price = models.FloatField(null = True, blank = True, verbose_name='Цена')
exposed = models.DateTimeField(default=timezone.now, verbose_name= 'Выставлен')
created = models.DateTimeField(auto_now_add=True, verbose_name= 'Создан')
updated = models.DateTimeField(auto_now=True, verbose_name= 'Обновлен')
status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='ожидается', verbose_name = 'Статус')
category_name = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Каталог', related_name = 'category_name')
category_slug = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Слаг каталога', related_name = 'category_slug')
goods_slug = models.SlugField(max_length=250, unique = True, verbose_name = 'Слаг товара')
objects = models.Manager()
published = PublishedManager()
class Meta:
verbose_name_plural = 'Товары'
verbose_name = 'Товар'
ordering = ('-exposed',)
def __str__(self):
return self.goods_name
def info_as_list(self):
return self.goods_info.split('\n')
def less_goods_info(self):
return u"%s..." % (self.goods_info[:150],)
class Category(models.Model):
category_name = models.CharField(max_length = 70, verbose_name='Каталог')
category_info = models.TextField(blank = True, verbose_name='Информация о каталоге')
category_image = models.ImageField(upload_to = 'images/categories', verbose_name = 'Изображение категории')
category_slug = models.SlugField(max_length=250, unique = True, verbose_name = 'Слаг каталога')
objects = models.Manager()
class Meta:
verbose_name_plural = "Каталоги"
verbose_name = "Каталог"
ordering = ('category_name',)
def __str__(self):
return self.category_name
Т.к. везде, где фигурируют товары, нужно использовать не только название каталога, но и его слаг, то приходится делать дополнительный запрос к бд. Чтобы решить эту проблему, подумывала сделать 2 ключа к Товарам - имя каталога и его слаг. Для этого нужно использовать related_name, но такой код
category_name = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Каталог', related_name = 'category_name')
category_slug = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Слаг каталога', related_name = 'category_slug')
не работает. Работает кое-как, если в related_name указать немного измененное имя поля (я добавила f в начале), что-то вроде
category_name = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Каталог', related_name = 'fcategory_name')
category_slug = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Слаг каталога', related_name = 'fcategory_slug')
А это ошибка, при создании миграций
SystemCheckError: System check identified some issues:
ERRORS:
ecoshop.Goods.category_name: (fields.E302) Reverse accessor for 'Goods.category_name' clashes with field name 'Category.category_name'.
HINT: Rename field 'Category.category_name', or add/change a related_name argument to the definition for field 'Goods.category_name'.
ecoshop.Goods.category_name: (fields.E303) Reverse query name for 'Goods.category_name' clashes with field name 'Category.category_name'.
HINT: Rename field 'Category.category_name', or add/change a related_name argument to the definition for field 'Goods.category_name'.
ecoshop.Goods.category_slug: (fields.E302) Reverse accessor for 'Goods.category_slug' clashes with field name 'Category.category_slug'.
HINT: Rename field 'Category.category_slug', or add/change a related_name argument to the definition for field 'Goods.category_slug'.
ecoshop.Goods.category_slug: (fields.E303) Reverse query name for 'Goods.category_slug' clashes with field name 'Category.category_slug'.
HINT: Rename field 'Category.category_slug', or add/change a related_name argument to the definition for field 'Goods.category_slug'.
Как уже сказала, с добавлением f оно заработало. Но при создании товара в админ панели возникает проблема. Когда я выбираю для товара каталог (допустим, растения), то поле слага каталога показывает не слаг растения, а список всех каталогов. Скажите пожалуйста, как можно сделать 2 ключа к товарам (каталог и его слаг), чтобы в админке не выбирать еще и слаг для товара (ведь в модели каталога он автоматически создается). То есть выбрать каталог товара, а слаг автоматически выбирается этого каталога.
К сожалению, информации по этому вопросу толком не нашла. Вопрос банальный, но поможет любой совет. Спасибо заранее.
(Вот так в админке выглядит, не знаю уже что с этим делать (:3 」∠) )
Ответы (1 шт):
Если вам для какой-то цели нужно использовать слаг каталога применительно к товару, то не нужно создавать дополнительные внешние ключи и делать дополнительные запросы к БД.
Всё можно получить из объектной модели.
Пример:
goods_item = Goods.objects.get(pk=1)
goods_slug = goods_item.category.slug
Соответственно в модели сущности товара надо исправить
category_name = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Каталог', related_name = 'category_name')
category_slug = models.ForeignKey('Category', on_delete=models.PROTECT, null = True, verbose_name = 'Слаг каталога', related_name = 'category_slug')
goods_slug = models.SlugField(max_length=250, unique = True, verbose_name = 'Слаг товара')
на приблизительно следующее:
category = models.ForeignKey(Category, on_delete=models.PROTECT)
