22.06.2009 22:04

  1. alTus

    0 ↑
    0 ↓
    Здравствуйте!

    Упрощенно, есть 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 на страницу)
    Мне кажется, как-то не очень.

    Получение в цикле связанных фоток отдельно для каждого товара тоже не очень хорошо.

    Размышляю в сторону запроса с джойном, но пока что-то ничего толкового не надумал.
  2. anonymous

    0 ↑
    0 ↓
    Мне кажется, как-то не очень.


    Отчего же, вполне вариант.

    Завести картинке дополнительное поле, которое помечает, что именно она будет показываться (например, is_featured). Потом:

    
    elements = CatElement.objects.filter(...).order_by(...)
    pictures = CatPicture.objects.filter(is_featured=True, pk__in=elements)
    


    Получится 1 запрос (правда с вложенным SELECT).
  3. Анонимно

    0 ↑
    0 ↓
    Да, дополнительное поле надо. Без него как-то не очень. И если есть потребность в порядке загрузок картинок не только для вышеописанного случая, я бы делал не BooleanField, а PositiveSmallIntegerField, куда бы и заносился порядок загрузки картинок.
  4. Михаил

    0 ↑
    0 ↓
    может в CatElement добавить поле main_picture = ForeignKey('CatPicture',....,null=True) и выставлять его в методе CatPicture.save. а ри выборке указывать select_related("CatPicture").
  5. alTus

    0 ↑
    0 ↓
    Спасибо, то что надо. Теперь о развитии событий :)

    Попробовал реализовать способ [от Михаила].

    Добавил 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 вызывать в начале но как-то не очень помогло.
  6. Михаил

    0 ↑
    0 ↓
    1) вообще обычно когда один ссылается на другого база на PostgreSQL не позволит так удалить. У вас какая база?
    2) непонятно где у вас self.catpicture_set.filter(element=self.id).order_by('id')[0:1] вызывается, в каком методе....
  7. alTus

    0 ↑
    0 ↓
    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? )
  8. Кажется, вы пытаетесь заново изобрести select_related.

  9. alTus

    0 ↑
    0 ↓
    Разве?
    Насколько я понимаю, related был бы, если бы у меня была ссылка в CatElement на CatPicture.
    А у меня наоборот, в CatPicture стоит ForeinKey на CatElement.

    Да и вопрос теперь, в основном, не в том, как получить эти данные, а в том - как их в шаблон передавать (последний абзац моего предыдущего поста).

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.