Бекенд на Django, Урок 8: Annotate и агрегация

Поделиться
HTML-код
  • Опубликовано: 8 ноя 2024

Комментарии • 97

  • @dodokwak
    @dodokwak 4 года назад +1

    Спасибо. Очень помогает,когда "понимал,понимал про annotate" и теперь в конце концов допонимался.

  • @standust119
    @standust119 4 года назад +2

    Спасибо за очень полезную информацию!

  • @progmain5237
    @progmain5237 2 года назад +6

    Спасибо за видео!
    P.S. Есть еще пару пожеланий:
    1. Хотя бы раз в 3 урока было бы неплохо проводить манипуляции с html что бы наглядно было видно для чего мы все это делали.
    2. подумал, столкнувшись с этой проблемами, что если вы даете "домашку" (а это полезно), то в следующем видео ее показывали

  • @RomanBog
    @RomanBog Год назад +1

    Спасибо. Отличный урок, правда пришлось потратить весь день, чтобы разобраться, но без такой практики освоить annotate() было бы тяжелее.

  • @ЛёшаСидорин
    @ЛёшаСидорин 4 года назад +1

    очень крутой урок
    спасибо большое)

  • @nix7705
    @nix7705 2 года назад +1

    Хм, userbookrelation__like, это как бы userbookrelation__set, только к одному полю like и мы подбираемся к лайкам через foreign key в userbookrelation модели.
    А можно (но не нужно) найти юзеров которые поставили лайк и посчитать их)
    Book.objects.get(name="abc").readers.filter(userbookrelation__like=True).count()
    Спасибо за урок

  • @dimuha82
    @dimuha82 Год назад +1

    В одном проекте удалось аннотациями-агрегациями и прочими релейтедами уменьшить кол-во SQL-запросов с 54 до 6! )))

  • @jamjam3337
    @jamjam3337 8 месяцев назад

    спасибо!😎

  • @ФоксиДжентельмен

    лучший!

  • @dodokwak
    @dodokwak 4 года назад +1

    На ночь глядя, пришло вот такое решение последней задачи: Book.objects.annotate(price_with_discount=F('price')-F('discount'))
    . Что-то решила discount == models.DecimalField(...), чтобы с приведением типов данных не морочиться.

  • @dizzivoneverec2737
    @dizzivoneverec2737 3 года назад +1

    Пишу комментарий чтобы по быстрей вышли новые ролики))

  • @lionshg
    @lionshg 4 года назад +2

    Отлично,спасибо! По возможности больше "фич", "хаков" и "штучек" в коде ), этого очень не хватает при изучении, и мало кто делиться подобными вещами. Вы случайно на Java не пишите? Вот бы подобный курс по Spring MVC )

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад

      Стараюсь чтобы все было просто и с большим функционалом. Фичи и хаки не так часто получается сделать в тестовых условиях, тут как-бы нет реальных проблем, которые нужно хакать. На Java не пишу, к сожалению

  • @kenan.recebli
    @kenan.recebli 3 года назад +2

    case when then можно было бы опустить и сразу передать userbookrelation__like=True в count

  • @watercrow1866
    @watercrow1866 4 года назад +1

    Круто, Спасибо! А почему второй 7ой урок?)

  • @chillside
    @chillside 2 года назад +1

    Спасибо! 2 часа пытался впихнуть эту анатацию в серилайзер, а его надо во вью 🤦‍♂️

  • @jimlabable
    @jimlabable 3 года назад +1

    Спасибо немного сложнее, но очень интересно. Жаль, что сейчас мало смотрят, но может? Нигде не могу найти ответ почему PyCharm упорно не хочет делать автоимпорт. Я уже даже и временную полную версию установил, все равно предлагает импорт только собственных моделей, а стороннее игнор. Поддержка молчит как в танке.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  3 года назад

      Первое что приходит в голову , не настроен virtual env или pip env . Но если делать как на видео то должен работать . Возможно проблема в ОС. У вас windows?

    • @jimlabable
      @jimlabable 3 года назад

      @@SeniorPomidorDeveloper Спасибо за ответ, достучался до поддержки, пока только попросили скрины, жду. Virtual env настроен, Mac os

  • @rostislavmalyshev1775
    @rostislavmalyshev1775 3 года назад

    Спасибо! Очень ценная информация. Аннотация - это красиво! Правильно ли я понял, что аннотация нужна, что бы не делать дополнительные поля в самой базе данных (лайк для каждой книги и пр.)?

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  3 года назад

      Не совсем . Аннотация нужна чтобы экономить запросы и при получении книг не проверять у каждого юзера лайкал ли он книгу

    • @rostislavmalyshev1775
      @rostislavmalyshev1775 3 года назад

      @@SeniorPomidorDeveloper Спасибо. Домашнее задание очень легкое :)

  • @koshakpoc2876
    @koshakpoc2876 2 года назад +1

    а как аннотировать только 1 элемент ?
    например у меня есть тест, где я проверяю test_get, но с выдачей 1 элемента по id
    если перед конструкцией с annotate сделать get(id=...) , то выдает ошибку
    нашел решение сделать через filter(id=...)
    но в сериализатор передавать books[0] , иначе тоже не работает

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  2 года назад +1

      Верно, один элемент больше никак не получится . Но тут как раз лучше не анатировать, а просто в функции вычислять

  • @watercrow1866
    @watercrow1866 4 года назад +3

    press F to pay respect to the homework =)

  • @dodokwak
    @dodokwak 4 года назад

    а если мы решаем задачу с discount-ом без сериализатора и api, то нужно созадавать метод в manager-е модели с annotate quesrySet-a? Спасибо.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад +1

      Да тут сериализатор и апи не важны . Тут именно фишка в том что вычисления должны быть в базе , остальное можно по разному делать . Можно создать метод в менеджере или не создавать . Главное правильно queryset написать . Он может быть во вью или в любом другом месте .

    • @dodokwak
      @dodokwak 4 года назад +1

      @@SeniorPomidorDeveloper Спс. В любом случае данное задание помогло мне совместить пред-ие знания об annotate and F().
      Почему-то запомнила раньше,что annotate используется в основном только по отношению к связанной через FK таблице, а F() - это очень приближённый к базе данных и соот-но быстрый способ изменить сразу ВСЕ значения в колонке таблицы (например: всем товарам сделать скидку, всем сотрудникам повысить зарплату). Однако совмещение этих методов оказалось применимо внутри одной таблицы .
      Ну и пришлось в очердной раз понять глубину своего невежества, прочитав статью об ORM : под девизом "simple queries - Managers, complex queries - QuerySets " (medium.com/@jairvercosa/manger-vs-query-sets-in-django-e9af7ed744e0). + ещё нашла кучу неведомых зверей типа OuterRef, Subquery in docs, которые тоже ждут своей очереди.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад

      Да, тема очень большая ! Рад что получается и приходит понимание .

  • @U7116-k7d
    @U7116-k7d Год назад

    Извините за предидущий огромный комментарий (который удалился), вроде решил проблему, так и не понял в чем дело, переписал файлы serializers и test_serializers и заработало. Где то была ошибка которую я так и не нашел )

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад

      Да, этот ютюб постоянно удаляет комментарии, не знаю почему. Иногда из-за ссылок, иногда просто так.
      Хорошо что проблема решилась . Если что могу ссылку прислать на репозиторий

    • @U7116-k7d
      @U7116-k7d Год назад

      @@SeniorPomidorDeveloper так я с вашего GitHub и взял код, долго сравнивал со своим, так и не нашел отличия ) В итоге вставил ваш код в эти файлы, так как свой я редактировал в попытках найти причину. Видимо опять где то одна буква или запятая делала всю погоду) Чем плох Python это форматирование кода через табы и пробелы, в итоге даже неверный отступ в один пробел может сломать код.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад

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

    • @Sergey-cz7ym
      @Sergey-cz7ym Год назад

      @@U7116-k7d в пайчарме есть функция сравнить два файла или сравнить файл с буфером обмена, удобно, можно копировать чужой код в буфер и сравнивать со своим файлом

  • @Николай-п8и2в
    @Николай-п8и2в 4 года назад +3

    Почему то возникает ошибка при создании юзеров в тестах : ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности "auth_user_username_key"
    DETAIL: Ключ "(username)=(user1)" уже существует.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад +1

      Что-то не так в конфгурации тестов. Они должно каждый раз на новой базе проходить. Можно попробовать удалить базу данных проекта и почистить базы, если какие-то еще лишние тестовые есть

    • @pavelv3913
      @pavelv3913 3 года назад

      @@mirok8658 Спасибо, это сработало.

    • @point_crash
      @point_crash Год назад

      Такая же история. И именно в тесте сериализатора! Почистил базу, но после прогона зашел проверить и тест создал в базе трех пользователей и ещё две книги. Не могу понять почему так происходит.

    • @dotco22
      @dotco22 Год назад

      @@point_crash Вряд ли это еще актуально, но возможно из-за использование TestCase из юниттестов, вместо джанги

    • @AIKgamescool
      @AIKgamescool Год назад

      @@dotco22 Спасибо. Правда решило проблему.

  • @RockstarAlexander
    @RockstarAlexander 2 года назад

    Супер

  • @МаксГла
    @МаксГла 5 месяцев назад

    тесты сериалайзера создают записи в базе данных и неудаляют их... второй раз тесты не проходят пока их не удалиш, в чём может быть проблема?

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  5 месяцев назад

      Хм. Может класс тестов не TestCase. Другой причины сложно себе представить

    • @МаксГла
      @МаксГла 5 месяцев назад

      почистил базу и from rest_framework.test import APITestCase и унаследовать сериалайзер тест от него, помогло.

  • @montyputon
    @montyputon 3 года назад

    А есть где нибудь архивчик с этим проектом?

  • @wandos777
    @wandos777 2 года назад

    может кто подскажет, я как то поменял название таблицы ALTER TABLE books_shop_book RENAME TO books_shop; и потом django при отработке url выдает такую ошибку: django.db.utils.ProgrammingError: ОШИБКА: отношение "books_shop_book" не существует. Я так понял, что старое отношение осталось и как можно "безболезненно" поменять название таблицы ?) При чем если меняю название таблицы обратно на "books_shop_book", то все окей, django видит эту таблицу. Что то мне подсказывает, что лучше не менять название таблицы, судя по различным источникам, но все же хочется до истины докопаться. Думал кешируются где данные эти, почистил в __pycache__ все, что было связано с БД, но, увы, это результат не принесло. Видимо, где то хранится настройка..

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  2 года назад +1

      Вы можете в момент создания модели указать db_table , и тогда можно будет его менять когда хотите и модель должна продолжать работать . Но если имя таблицы создано автоматически то лучше уже не не переименовывать

  • @endfine9230
    @endfine9230 8 месяцев назад

    Здравствуйте, спасибо за курс, также спасибо, что учите как правильно писать тесты, прививаете эту хорошую привычку нам с самого начала обучения!! У меня вопрос: оптимально ли мое решение для сложного задания, а именно, я создал булевое поле discount в модели Book, и если оно True тогда annotate считает price with discount:
    Book.objects.all().annotate(price_w_discount=Case(When(discount=True, then=F('price')-100)))
    price_w_discount создается в сериализаторе

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  8 месяцев назад +1

      Здравствуйте ! Рад что курс понравился!
      Вроде бы, решение хорошее. Единственное, я бы вынес число 100 в переменную , куда-то. Лучше в самом qs использовать переменные , чтобы не хардкодить

    • @endfine9230
      @endfine9230 8 месяцев назад

      @@SeniorPomidorDeveloper Спасибо, исправлюсь 😅

  • @Sergey-cz7ym
    @Sergey-cz7ym Год назад

    Мдя, с annotate у меня как то совсем грустно. вообще ни чо не понял, где вообще можно почитать как строить такую мудрёную конструкцию как на 16:17, тут получается типа match - case c условием, но как узнать что так можно было? от фонаря такую конструкцию не напишешь... Когда-то мне казалось что лямбда и рекурсия это что то запутанное, но теперь я понимаю что то был просто сахар, на уровне детского сада.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад +1

      Я тоже это в голове не держу . Точно не напишу по памяти такой кейс с Case, When, then=1. Просто я примерно представляю возможности ORM и когда есть подобная задача то начинаю гуглить как через ORM это сделать.
      Тут задача это главное. Без нее я бы и не подумал копаться в этом .

    • @Sergey-cz7ym
      @Sergey-cz7ym Год назад

      @@SeniorPomidorDeveloper Спасибо, немного упокоили ), а то я уже совсем скис )

  • @newdisease1991
    @newdisease1991 2 года назад

    В вашей реализации лайки получаются неуникальными. Один пользователь может миллион раз лайкать одну книгу. А для того чтоб убрать лайк по факту нужно передавать "False". Причем когда несколько "True" от этого пользователя, то получится каша))

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  2 года назад

      Всегда есть над чем работать

    • @newdisease1991
      @newdisease1991 2 года назад

      @@SeniorPomidorDeveloper
      я решил эту проблему, добавив в модель мета класс с "UniqueConstraint(fields=['user', 'book'], name='unique-like')"
      тесты проходит, больше одного лайка не ставит. надеюсь, что это хорошее решение)

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  2 года назад +2

      Супер! Спасибо. Надо будет учесть в следующих курсах

    • @newdisease1991
      @newdisease1991 2 года назад

      @@SeniorPomidorDeveloper я немного дальше пошел. Сделал так, чтобы при отправке запроса лайк менялся на True или False автоматически, без отправки тела запроса. Во вью переопределил метод perform_update. Ппц как долго искал информацию, а решение оказалось очень простым))
      def perform_update(self, serializer): fav_post = self.get_object() if fav_post.like: serializer.save(like=False) else: serializer.save(like=True)
      Респект за уроки. Очень помогают в развитии. Ускорили меня раз в 150)

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  2 года назад +3

      Супер! Можно ещё типа так упростить
      serializer.save(like=not bool(fav_post.like))

  • @НикитаЗарецкий
    @НикитаЗарецкий 4 года назад

    добрый день
    почитал документацию и нашел про Sum, написал:
    books = Book.objects.all().annotate( annotated_likes=Count(Case(When(userbookrelation__like=True, then=1))), rating=Avg('userbookrelation__rate'), price_discount=Sum(F('price')-F('discount'), output_field=FloatField())).order_by('id')
    но оно выдает лютую дичь, погуглил про F не нашел ответ на свой впорос. Что в данном случае делает функция F? и как правильно делается дз?

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад

      Не буду спойлерить правильный ответ. А F() нужен только для того чтобы обратится к определённому полю. Сам по себе он не несёт никакой функции .

    • @dodokwak
      @dodokwak 4 года назад

      а зачем суммировать в price_discount? и ещё, меня так напугали FloatField в отношении денежных расчётов, что я вместо них повсеместно применяю поле DecimalField

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад

      Decimal это правильно. Суммировать ? Вроде нужно из цены вычесть скидку ..

    • @НикитаЗарецкий
      @НикитаЗарецкий 4 года назад

      @@SeniorPomidorDeveloper я наткнулся на пример где Sum(F(..) /F(..)) и подумал если деление стоит, то может и минут прокатит

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  4 года назад

      Может и прокатит :) Тут не угадаешь, нужно просто попробовать ! )

  • @Webian
    @Webian Год назад

    Невоспронимаемая информация начиная с 7 видео, без разяснения ничего не понятно. Хотя до этого много очень полезного узнал.

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад +1

      Сочувствую. Посмотрите последний курс, Оптимизация. Там похожие вещи и будет понятнее, я думаю.

  • @haydarshoh-sh
    @haydarshoh-sh Год назад

    final_price = StoreBook.objects.filter(id=self.book1.id).annotate(discounted=Sum('price')-Sum('discount')).order_by('id')
    Задание по окончанию урока:
    пол часа сидел с этим заданием, по ходу выполнения многое узнал но не смог найти другого решения кроме этого. Не делая дополнительный запрос вычитать сумму из поля скидки из поле цены которые находятся в одной таблице(там было макс, мин, сум итд, но не было вычитание)

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад +1

      Честно говоря, я уже плохо помню это видео и задание. Но если оно помогло разобраться то я очень рад.

  • @ЕлданаКеңес
    @ЕлданаКеңес Год назад

    django.db.utils.IntegrityError: duplicate key value violates unique constraint "auth_user_username_key"
    DETAIL: Key (username)=(user1) already exists.
    Вот такая ошибка выходить после запуска теста, 17:40

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад +1

      Надо почистить тестовую базу наверно. Или перезапустить тест , по идее скрипт должен сам предложить ее почистить

    • @ЕлданаКеңес
      @ЕлданаКеңес Год назад

      аа, ок спасибо@@SeniorPomidorDeveloper

    • @ЕлданаКеңес
      @ЕлданаКеңес Год назад

      какие именнно таблциы нужно почистить ?

    • @SeniorPomidorDeveloper
      @SeniorPomidorDeveloper  Год назад

      Вся тестовая база перед запуском тестов должна удаляться. Это другая база , обычно называется с префиксом test_* или типа того

    • @ЕлданаКеңес
      @ЕлданаКеңес Год назад

      не могу решить, что можно делать ? с гита пуллит ?
      @@SeniorPomidorDeveloper

  • @ЛёшаСидорин
    @ЛёшаСидорин 4 года назад

    очень крутой урок
    спасибо большое)