P
PisychНаурыз 28, 2023, 10: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, 9: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 Т.Ж.
                          • (өңделген)

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

                            Пікірлер

                            Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
                            Кіріңіз немесе Тіркеліңіз
                            OI
                            • Ora Iro
                            • Жел. 24, 2024, 6:38 Т.Ж.

                            C++ - Тест 001. Первая программа и типы данных

                            • Нәтиже:40ұпай,
                            • Бағалау ұпайлары-8
                            AD

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

                            • Нәтиже:50ұпай,
                            • Бағалау ұпайлары-4
                            m
                            • molni99
                            • Қаз. 26, 2024, 1:37 Т.Ж.

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

                            • Нәтиже:80ұпай,
                            • Бағалау ұпайлары4
                            Соңғы пікірлер
                            ИМ
                            Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
                            Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                            Evgenii Legotckoi
                            Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
                            Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                            A
                            ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
                            Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                            ИМ
                            Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
                            Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                            d
                            dblas5Шілде 5, 2024, 11:02 Т.Ж.
                            QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                            Енді форумда талқылаңыз
                            Evgenii Legotckoi
                            Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
                            добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                            t
                            tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
                            google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                            NSProject
                            NSProjectМаусым 4, 2022, 3:49 Т.Ж.
                            Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
                            9
                            9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
                            Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

                            Бізді әлеуметтік желілерде бақылаңыз