в Django проекте. При аннотировании в представлениях появляется ошибка, что элемент не определен - PullRequest
0 голосов
/ 03 февраля 2020

Я знаю, что эта тема упоминалась несколько раз, но я не могу найти решение своей проблемы. Поэтому примите мои извинения за повторный запрос.

У меня есть фильтр на основе условий, который мне не подходит.

вот мой файл models.py:

class Itemslist(models.Model):
    safety_stock = models.DecimalField(blank=True, null=True, max_digits=19, decimal_places=0)
    current_stock = models.DecimalField(max_digits=19, decimal_places=0)

    def above_below_ss(self):
        ab = Decimal(self.current_stock-self.safety_stock)
        return round(ab,0)


    def __str__(self):
        return self.item_n

Извините, нужно исправить отступ, так как все это относится к одному классу модели.

и вот что у меня есть в файле views.py:

from .models import *

def toorder(request):
    # toorder=Itemslist.objects.all
    sorted=Itemslist.objects.annotate(dontshow=above_below_ss()).exclude(dontshow__gt=0)
    context={ 'sorted': sorted }
    return render(request, 'toorder.html', context)

Так вот проблема: когда я использую

toorder=Itemslist.objects.all

все работает, но когда я пытаюсь это сделать:

sorted=Itemslist.objects.annotate(dontshow=above_below_ss()).exclude(dontshow__gt=0)

не работает.

Интересно Дело в том, что раньше он работал, но мой код не работал без копии (во время резервного копирования, что довольно забавно),

И теперь это не работает.

Я получаю это сообщение:

NameError at /toorder
name 'above_below_ss' is not defined
Request Method: GET
Request URL:    http://localhost:8000/toorder
Django Version: 2.2.5
Exception Type: NameError
Exception Value:    
name 'above_below_ss' is not defined
Exception Location: /Users/artursjermolickis/projects/osmiocenter/mysite/itemlist/views.py in toorder, line 220
Python Executable:  /Users/artursjermolickis/projects/osmiocenter/venv/bin/python3
Python Version: 3.7.4
Python Path:    
['/Users/artursjermolickis/projects/osmiocenter/mysite',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python37.zip',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/lib-dynload',
 '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf',
 '/Users/artursjermolickis/projects/osmiocenter/venv/lib/python3.7/site-packages/odf']

Если вам нужно больше кусков кода от меня, пожалуйста, просто скажите мне, что вам нужно.

Действительно надеюсь, что Вы можете помочь мне здесь.

Вот дополнительные комментарии к моему вопросу.

Необходимо отфильтровать результат по математической функции.

в качестве примера, который я разместил safety_stock, и предоставленное решение работает для этого.

Но, как вы уже упоминали, мне нужна сортировка базы данных по более сложной функции, поэтому лучше делать это в моделях. py вместо того, чтобы делать это в vews.py, чтобы я мог использовать его позже. Итак, код, который я хочу заменить safety_stock следующим:

def safe_stock(self):
        if self.safety_stock ==0:
            ss= (self.sales6mavgs()+self.stdev())*(self.lead_time+self.bookingterms)
        else:
            ss=Decimal(self.safety_stock)
        return Decimal(ss.quantize(Decimal('1'),rounding=ROUND_UP))

Итак, из ваших предложений я понял, что мне нужно реализовать ExpressionWrapper.

Как реализовать его с помощью ExpressionWrapper

Теперь на вопрос дан ответ, подробности см. ниже Я добавил менеджера в мои models.py:

class ToOrderManager(models.Manager):

    def get_queryset(self):
        return super(ToOrderManager, self).get_queryset().annotate(
        dontshow=Round(ExpressionWrapper((F('current_stock')-F('safety_stock')), output_field=DecimalField()),0)
        ).annotate( leadtime=ExpressionWrapper(F('lead_time'), output_field=DecimalField())
        ).exclude(dontshow__gte=0).exclude(leadtime=0)

Эти строки были добавлены в мою основную модель:

objects = models.Manager()
toorderobjects = ToOrderManager()

и мой views.py теперь выглядит так:

def toorder(request):
    sorted=Itemslist.toorderobjects.all()
    context={ 'sorted': sorted }
    return render(request, 'toorder.html', context)

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

Большое спасибо за обмен знаниями !!!

1 Ответ

3 голосов
/ 03 февраля 2020

Я не думаю, что это dontshow=above_below_ss() было рабочим, потому что это метод экземпляра, который означает, что вы сначала выбрали одну запись, а затем назвали ее record.above_below_ss(). Вместо этого вы можете написать этот метод как часть аннотации, используя fun c и упаковщик выражений :

models.py

from django.db.models import Func

class Round(Func):
    function = 'ROUND'
    arity = 2

views.py

from django.db.models import DecimalField, ExpressionWrapper, F
from .models import Round

sorted=Itemslist.objects.annotate(dontshow=Round(ExpressionWrapper(F('current_stock') - F('safety_stock'), output_field=DecimalField()))).exclude(dontshow__gt=0)

Если вы хотите использовать это повторно, вы можете переместить запрос в manager и назвать его. Тогда вместо того, чтобы каждый раз писать длинный запрос, вы просто используете Itemslist.objects.whatever_name_you_chose()

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