-
Здравствуйте!
Упрощенно, есть 2 модели: товар и картинки к нему.
class CatElement(models.Model): title = models.CharField(........) class CatPicture(models.Model): picture = ImageWithThumbnailsField(.......) # это поле из sorl element = models.ForeignKey('CatElement', blank=False, null=False)
Задача в принципе тривиальная - вывод на страницу товаров с их картинками.
Но надо, чтобы выводилась именно первая загруженная фотка (они грузятся через инлайн на странице товара) - то есть получается, что это фотка с наименьшим ID для данного товара.
Объекты я получаю обычным CatElement.filter(**filters).order_by(....)
И вопрос весь в том, как лучше эти связанные фотки получать.
Хотелось бы объектами, т.к. у меня там превьюшки.
Хороший ли вариант - выбрать все ID товаров данной страницы и сделать запрос с большим количеством OR: id=1 OR id=2 и так далее? (записей будет 10-20 на страницу)
Мне кажется, как-то не очень.
Получение в цикле связанных фоток отдельно для каждого товара тоже не очень хорошо.
Размышляю в сторону запроса с джойном, но пока что-то ничего толкового не надумал. -
Мне кажется, как-то не очень.
Отчего же, вполне вариант.
Завести картинке дополнительное поле, которое помечает, что именно она будет показываться (например, is_featured). Потом:
elements = CatElement.objects.filter(...).order_by(...) pictures = CatPicture.objects.filter(is_featured=True, pk__in=elements)
Получится 1 запрос (правда с вложенным SELECT). -
Да, дополнительное поле надо. Без него как-то не очень. И если есть потребность в порядке загрузок картинок не только для вышеописанного случая, я бы делал не BooleanField, а PositiveSmallIntegerField, куда бы и заносился порядок загрузки картинок.
-
может в CatElement добавить поле main_picture = ForeignKey('CatPicture',....,null=True) и выставлять его в методе CatPicture.save. а ри выборке указывать select_related("CatPicture").
-
Спасибо, то что надо. Теперь о развитии событий :)
Попробовал реализовать способ [от Михаила].
Добавил ForeignKey в CatElement и переопределил метод save у модели (!)CatElement
def save(self, force_insert=False, force_update=False): pic = self.catpicture_set.filter(element=self.id).order_by('id')[0:1] if pic and not pic[0] == self.picture: self.picture = pic[0] super(CatElement, self).save(force_insert, force_update)
И тут 2 проблемы сразу:
1) если у нас есть объект товара и для него например одна фотка, то если её удалить из инлайна этого товара, то удаляется и сам товар (как я понял - из-за того, что у этой фотки стоит foreignkey на этот товар и наоборот - сам товар ссылается теперь на фотку, и все связанные объекты удаляются автоматом)
2) при самом первом добавлении товара его id неизвестен, и поэтому self.catpicture_set.filter(element=self.id).order_by('id')[0:1] ни к чему не приводит. можно ли без сигнала post_save обойтись? то есть именно в этом методе узнать id? пробовл super().save вызывать в начале но как-то не очень помогло. -
1) вообще обычно когда один ссылается на другого база на PostgreSQL не позволит так удалить. У вас какая база?
2) непонятно где у вас self.catpicture_set.filter(element=self.id).order_by('id')[0:1] вызывается, в каком методе.... -
1) это сейчас на тестовом движке - sqlite соответственно. но мне казалось что база тут не при чем, ведь django по идее сам связанные удаляет, а не база за него это автоматом
2) хм, ну я там вроде указал, что этот метод определен в модели CatElement (в файле models.py)
—————
может, кому пригодиться - сейчас я сделал через OR:
это код вьюшки по объединению в один массив фоток и товаров.
# получаем все фотки товаров данной страницы all_pictures = CatPicture.objects.filter( element__in=goods.object_list).order_by('id') # в словарь picrures накапливаем первые фотки # каждого товара; ключ массива - ID товара pictures = {} compare_id = False for pic in all_pictures: if compare_id == pic.element_id: continue pictures[pic.element_id] = pic.picture compare_id = pic.element_id # объединяем - доабавляем в каждый товар поле картинки full_object_list = [] for item in goods.object_list: if item.id in pictures: item.main_pic = pictures[item.id] else: item.main_pic = False full_object_list += [item] goods.object_list = full_object_list
Вопрос концептуальный, так сказать: всегда ли придется действовать так при передачe каких-то связанных данных в шаблон.
Примеров миллион - например книги и авторы, которых надо выводить в списке - также мучиться с объединением? В PHP я делал просто связь по ID, но в django-шаблонах нельзя использовать конструкции типа authors[ID].
Думается, все с этим сталкивались - какой тут django-way? ) -
Кажется, вы пытаетесь заново изобрести select_related.
-
Разве?
Насколько я понимаю, related был бы, если бы у меня была ссылка в CatElement на CatPicture.
А у меня наоборот, в CatPicture стоит ForeinKey на CatElement.
Да и вопрос теперь, в основном, не в том, как получить эти данные, а в том - как их в шаблон передавать (последний абзац моего предыдущего поста).
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

