P
Pisych28 марта 2023 г. 22:59

Как подсчитать количество по условию?

Добрый день! К примеру, такая таблица:

Товары могут быть с одинаковыми названиями, но разными ценами. Есть поле uniq_field (название, конечно, неверное, оно не уникальное, но оно идентифицирует товар в зависимости от id и цены... Может, оно вообще не нужно :)
Как мне получить в запросе количество по каждому товару в зависимости от цены? То есть товару с таким то названием и по цене 100 руб. в наличии столько-то, а вот такой же, но по цене 200 - столько...
Я пробовал получать уникальный set с uniq_id, затем в цикле обходить всю таблицу для каждого значения set, подсчитывать количество и т.д. Но это же неправильно? Оно работает, но долго на больших таблицах. Есть ли способ лучше? Как сделать такой запрос с использованием Sum?
Спасибо!
В общем, в итоге должно получится нечто типа этого:

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

13
Evgenii Legotckoi
  • 29 марта 2023 г. 4:09

Добрый день.
Да, здесь нужно средствами запросов к базе данных работать. Здесь нужно использовать annotate и values

Не уверен, что напишу полностью правильно без тестирования на кошках, но должно выглядеть как-то так

tovars = Tovar.objects.values("id_tovar", "price").annotate(count=Sum("kol"))

По идее, это должно взять все одинаковые значения для id товара и его цены и проссумировать столбец kol. В результате будет создан временный queryset со структурой id_tovar price count

Его уже можно будет итерировать примерно так или подобный способом

for tovar in tovars:
    print(tovar.id_tovar, tovar.price, tovar.count)

Операции annotate тоже затратные по времени, но этим будет заниматься база данных, поэтому это должно в любом случае работать быстрее

    P
    • 29 марта 2023 г. 4:31

    Да я так и пробую.

    Вот я получаю set, тут вроде все как надо

     uniqidset=set(JurnalDoc.objects.values_list('title__title','price'))
        for i in uniqidset:
            print(i)
    

    Вывожу в консоль: все верно, нет повторяющихся значений...
    Quit the server with CTRL-BREAK.
    ('Товар2', 50.0)
    ('Товар1', 200.0)
    ('Товар 3', 100.0)
    ('Товар1', 100.0)

    Добавляю annotate:

     uniqidset=set(JurnalDoc.objects.values_list('title__title','price').annotate(count=Sum('kol')))
        for i in uniqidset:
            print(i)
    

    Упс!

    ('Товар2', 50.0, 30.0)
    ('Товар 3', 100.0, 45.0)
    ('Товар1', 100.0, 20.0)
    ('Товар2', 50.0, 20.0)
    ('Товар1', 200.0, 20.0)

    А я хотел бы получить
    ('Товар2', 50.0, 50.0)
    ('Товар 3', 100.0, 45.0)
    ('Товар1', 100.0, 20.0)
    ('Товар1', 200.0, 20.0)
    Как можно сделать? Спасибо!

      Evgenii Legotckoi
      • 29 марта 2023 г. 4:59

      Должно работать. Покажите код моделей, ибо меня смущает эта часть values_list('title__title' , по ходу у вас там всё несколько сложнее, чем вы показали изначально

        P
        • 29 марта 2023 г. 5:10
        class Nom(models.Model):
            title = models.CharField(max_length=150, verbose_name='Наименование', unique=True )
            izm=models.ForeignKey(Unit,verbose_name='Ед.изм.',on_delete=models.PROTECT)
            category = models.ForeignKey(Category, verbose_name='Категория', on_delete=models.PROTECT)
            srok=models.IntegerField(blank=True,default=0)
            updated_at = models.DateTimeField(auto_now=True, verbose_name='Создан')
            created_at = models.DateTimeField(auto_now_add=True, verbose_name='Обновлен')
            def __str__(self):
                return self.title
        
        class JurnalDoc(models.Model):
        
            oper=models.IntegerField(max_length=1,verbose_name='Операция')
            iddoc=models.ForeignKey(Jurnal,on_delete=models.PROTECT)
            title=models.ForeignKey(Nom,verbose_name='Наименование',on_delete=models.PROTECT)
            price=models.FloatField(verbose_name='Цена',default=0.0)
            kol = models.FloatField(verbose_name='Количество', default=0.0)
            podraz=models.ForeignKey(Podraz,on_delete=models.PROTECT,verbose_name='Подразделение')
            postav=models.ForeignKey(Postav,on_delete=models.PROTECT,verbose_name='Поставщик')
            obct=models.ForeignKey(Obct,on_delete=models.PROTECT,verbose_name='Объект')
            fio=models.ForeignKey(Fio,on_delete=models.PROTECT,verbose_name='Подотчетник')
            spis=models.ForeignKey(Spis,on_delete=models.PROTECT,null=True,blank=True,verbose_name='Причина списания')
            summa=models.FloatField(verbose_name='Сумма')
            nds=models.IntegerField(default=20,verbose_name='НДС')
            summawithnds=models.FloatField(verbose_name='Сумма с НДС')
            updated_at = models.DateTimeField(auto_now=True, verbose_name='Создан')
            created_at = models.DateTimeField(auto_now_add=True, verbose_name='Обновлен')
            uniqfield=models.CharField(max_length=250,verbose_name='Слаг')
            def __str__(self):
                return self.title
        
        

        Ну title наверное неудачное название поля... Логичнее было бы id_nomenklatura или id_nom... Но у меня оно так называется..

          Evgenii Legotckoi
          • 29 марта 2023 г. 5:23

          Хорошо, тогда должно быть достаточно использовать просто внешний ключ 'title' без поиска по заголовку в записи товара.
          Маловероятно, но что тогда выдаст это?

           uniqidset=set(JurnalDoc.objects.values_list('title','price').annotate(count=Sum('kol')))
              for i in uniqidset:
                  print(i)
          
            P
            • 29 марта 2023 г. 5:31

            (1, 200.0, 20.0)
            (3, 50.0, 20.0)
            (68, 100.0, 45.0)
            (3, 50.0, 30.0)
            (1, 100.0, 20.0)

              Илья Чичак
              • 29 марта 2023 г. 5:33

              это потому, что у вас

              uniqidset=set(JurnalDoc.objects.values_list('title__title','price').annotate(count=Sum('kol')))
              

              а надо

              uniqidset=set(JurnalDoc.objects.values('title__title','price').annotate(count=Sum('kol')))
              

              values вместо values_list

                P
                • 29 марта 2023 г. 5:35

                большое спасибо. завтра проверю. сейчас уже нет возможности:(

                  P
                  • 29 марта 2023 г. 21:15

                  А так выдает ошибку:

                  def GetActualData(request):
                      uniqidset=set(JurnalDoc.objects.values('title','price').annotate(count=Sum('kol')))
                      for i in uniqidset:
                          print(i)
                      return HttpResponse('OK')
                  

                    Evgenii Legotckoi
                    • 30 марта 2023 г. 1:14

                    Ну а подумать над ошибкой? ;-)

                    У вас dict в set не переводится, да и не нужно это там

                    ef GetActualData(request):
                        uniqidset=JurnalDoc.objects.values('title','price').annotate(count=Sum('kol')))
                        for i in uniqidset:
                            print(i)
                        return HttpResponse('OK')
                    
                      P
                      • 30 марта 2023 г. 2:34

                      А я уже третий день думаю :))
                      Я так тоже пробовал, вот результат:
                      {'title__title': 'Товар 3', 'price': 100.0, 'count': 45.0}
                      {'title__title': 'Товар1', 'price': 100.0, 'count': 20.0}
                      {'title__title': 'Товар2', 'price': 50.0, 'count': 30.0}
                      {'title__title': 'Товар2', 'price': 50.0, 'count': 20.0}
                      {'title__title': 'Товар1', 'price': 200.0, 'count': 20.0}
                      {'title__title': 'Товар1', 'price': 100.0, 'count': 20.0}
                      [30/Mar/2023 13:24:33] "GET /GetActualData/ HTTP/1.1" 200 2

                      А надо не два вот этих:
                      {'title__title': 'Товар2', 'price': 50.0, 'count': 30.0}
                      {'title__title': 'Товар2', 'price': 50.0, 'count': 20.0}
                      а один:
                      {'title__title': 'Товар2', 'price': 50.0, 'count': 50.0}
                      Вообще мне это нужно вот для чего - эти данные потом будут передаваться в option селекта и оператор при выборе будет видеть, сколько у него осталось товара по такой-то цене... Чтобы лишнего не отпустил:). Да и вообще для отчетов потом нужно... Вот и хочу такой хитрый запрос сделать. Я бы плюнул, создал бы временную таблицу, и записывал бы туда остатки. Циклом опять же... Но вот интересно, можно ли в принципе такой запрос сделать. Вроде как на Postgress есть distinct по определенному полю, но у меня sqlite :(
                      Может, есть все таки идеи, как это можно?
                      Спасибо!

                        Evgenii Legotckoi
                        • 30 марта 2023 г. 2:42
                        • Ответ был помечен как решение.

                        То есть у вас SQLite? А я думаю, почему это не работает.
                        Возможно проблема в отсутствии сортировки результатов. Попробуйте так

                        def GetActualData(request):
                            uniqidset=JurnalDoc.objects.values('title','price').annotate(count=Sum('kol')).order_by('title','price')
                            for i in uniqidset:
                                print(i)
                            return HttpResponse('OK')
                        
                          P
                          • 30 марта 2023 г. 2:50
                          • (ред.)

                          Да! Вот так работает! Огромное Вам спасибо!
                          ........

                            Комментарии

                            Только авторизованные пользователи могут публиковать комментарии.
                            Пожалуйста, авторизуйтесь или зарегистрируйтесь
                            AD

                            C++ - Тест 004. Указатели, Массивы и Циклы

                            • Результат:50баллов,
                            • Очки рейтинга-4
                            m
                            • molni99
                            • 26 октября 2024 г. 7:37

                            C++ - Тест 004. Указатели, Массивы и Циклы

                            • Результат:80баллов,
                            • Очки рейтинга4
                            m
                            • molni99
                            • 26 октября 2024 г. 7:29

                            C++ - Тест 004. Указатели, Массивы и Циклы

                            • Результат:20баллов,
                            • Очки рейтинга-10
                            Последние комментарии
                            ИМ
                            Игорь Максимов22 ноября 2024 г. 17:51
                            Django - Урок 017. Кастомизированная страница авторизации на Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                            Evgenii Legotckoi
                            Evgenii Legotckoi31 октября 2024 г. 19:37
                            Django - Урок 064. Как написать расширение для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                            A
                            ALO1ZE19 октября 2024 г. 14:19
                            Читалка fb3-файлов на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                            ИМ
                            Игорь Максимов5 октября 2024 г. 13:51
                            Django - Урок 064. Как написать расширение для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                            d
                            dblas55 июля 2024 г. 17:02
                            QML - Урок 016. База данных SQLite и работа с ней в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                            Сейчас обсуждают на форуме
                            m
                            moogo22 ноября 2024 г. 13:17
                            Mosquito Spray System Effective Mosquito Systems for Backyard | Eco-Friendly Misting Control Device & Repellent Spray - Moogo ; Upgrade your backyard with our mosquito-repellent device! Our misters conce…
                            Evgenii Legotckoi
                            Evgenii Legotckoi24 июня 2024 г. 21:11
                            добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                            t
                            tonypeachey115 ноября 2024 г. 12:04
                            google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                            NSProject
                            NSProject4 июня 2022 г. 9:49
                            Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…

                            Следите за нами в социальных сетях