Запрос Django ORM не выполняется, когда выполняется как запрос в postgresql - PullRequest
0 голосов
/ 11 октября 2018

У меня есть что-то вроде этой модели

class model(models.Model):
    order_created_time = models.DateTimeField(blank=False, null=False)

У меня есть запрос django, который сравнивает дату и время следующим образом -

filters = {'order_created_on__gte':'2018-10-10'}
queryset = model.objects.filter(**filters)
query = str(queryset.query)

Создает запрос - выберите ... где order_created_on> = 2018-10-10 00: 00: 00

При срабатывании на дБ выдается ошибка - синтаксическая ошибка в или около "00".

Если я запускаю тот же запрос вdb вручную, заменив дату на '2018-10-10', это работает.

Теперь я фактически попробовал следующие способы, но все запросы дают один и тот же текст в запросе db

filters = {'order_created_on__gte':datetime(2018-10-10)}
filters = {'order_created_on__year__gte':2018, 'order_created_on__month__gte':10, 'order_created_on__day__gte':10}

Также пытался использовать его в качестве строки, подобной этой -

filters['order_created_on__gte'] = "'{0}'".format(filters['order_created_on__gte'])

Указывается как недопустимый формат, ожидается 2018-10-10 00:00 [: 00] [TZ]

Также использовался фильтр диапазона, все вышеперечисленное вставляло этот текст в окончательный запрос -

where order_created_on >= 2018-10-10 00:00:00

Обновление часового пояса тоже не имело никакого эффекта, вместо простого удаления +5: 30 из запроса.

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

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

0 голосов
/ 13 октября 2018

Усталый от использования этого регулярного выражения при замене запроса, использовал этот подход.Просто установите фильтры с опцией или «ORM» или «RAW».Если он необработанный, он создаст запрос 'where'.Вы также можете добавить в него другие фильтры.

    # For ORM
    GET_SETTLEMENT_PARAM_QUERY_FORMATTING = {
    "settlement_no": {"query_text": "settlement_no__in", "list": True},
    "start_date": {"query_text": "start_date__gte", "list": False},
    "end_date": {"query_text": "end_date__lte", "list": False}
    }

    # For RAW query
    BAGSETTLEMENT_DOWNLOAD_PARAM_QUERY_FORMATTING_RAW = {
    "start_date": {"query_text": "created_on >= '{}'", "list": True, "ignore_format": True},
    "end_date": {"query_text": "created_on <= '{}'", "list": True, "ignore_format": True},
    "store_id": {"query_text": "store_id IN {}", "list": True},
    "brand_id": {"query_text": "brand_id IN {}", "list": True},
    "company_id": {"query_text": "company_id = {}", "list": False},
    "bag_id": {"query_text": "bag_id = {}", "list": False},
    "awb_number": {"query_text": "awb_number = {}", "list": False},
    "settlement_no": {"query_text": "settlement_no IN {}", "list": True},
    "settled": {"query_text": "settled = {}", "list": False}

}


    @query_params(formatting=GET_BAGSETTLEMENT_PARAM_QUERY_FORMATTING, query_type='ORM')
        def get(self, request):

            filters = parse_url_params(params=self.request.query_params, formatting=BAGSETTLEMENT_DOWNLOAD_PARAM_QUERY_FORMATTING_RAW, query_type='RAW')

            try:
                link = get_download_link(filters=filters,
                                             store_ids=request.store_ids,
                                             end_file_name=settlement_no)
                return Response({"link": link})
            except Exception as e:
                logger.critical('Bag Settlement Download Link Generation Failed')
                return Response({'link': None, 'error': 'Error while fetching data'})


def query_params(formatting, query_type):
    def assign_query_params(f):
        @wraps(f)
        def decorated_function(req, *args, **kwargs):
            try:
                request = req.request
            except AttributeError:
                request = req

            # print(request.store_ids)
            data = dict(request.GET)
            if data.get('store_id'):
                data['store_id'] = list(set(data.get('store_id')).intersection(set(request.store_ids)))
            else:
                data['store_id'] = request.store_ids

            request.filters = parse_url_params(params=data,
                                               formatting=formatting,
                                               query_type=query_type)
            return f(req, *args, **kwargs)

        return decorated_function

    return assign_query_params

def parse_url_params(params, formatting, query_type):
    """
    :param params: dictionary
    :param formatting: Formatting Dictionary
    :param query_type: ORM else RAW
    :return: filters
    """
    # print(params)
    filters = dict() if query_type == "ORM" else ''

    for key, value in formatting.items():
        param_value = params.get(key)
        if not param_value:
            continue
        query_text = value['query_text']

        if query_type == "ORM":
            query_value = param_value[0] if not value['list'] else param_value

            filters[query_text] = query_value

        else:
            if not value['list']:
                query_value = param_value[0]
            else:

                if value.get('ignore_format'):
                    query_value = param_value
                else:
                    z = str(param_value)
                    query_value = z.replace(z[0], '(').replace(z[len(z)-1], ')')
            syntax = query_text.format(query_value)
            filters += syntax if not len(filters) else ' AND '+syntax

    return filters

С его помощью вы можете получить как фильтры ORM, так и фильтры запросов RAW.Проблема, с которой я столкнулся, заключалась в том, что дата и время не вставлялись в виде строки, поэтому здесь я просто создал строку всех условий условия.

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

select * from table where {filters};

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

select * from table where {filters} order by {order_by}

Если вам нужно добавить еще один явный фильтр, вы можете сделать это следующим образом

select * from table where {filters} and store_id in {store_id};
0 голосов
/ 11 октября 2018

Django фактически не использует результат str(queryset.query) для запросов к базе данных.Причина этого довольно проста:

Базы данных принимают параметризованных запросов , поэтому Django фактически никогда не помещает параметры в запрос.Он отправляет строку запроса и список параметров отдельно в базу данных, которая выясняет, как с ней справиться.

print(SomeModel.objects.filter(foo=1).query.sql_with_params())

('SELECT "app_model"."id", "app_model"."some_column", "app_model"."foo" FROM "app_model" WHERE "app_model"."foo" = %s',
 (1,))

Затем для простоты все, что он делает, это делает простую подстановку строк, когда вы вызываете __str__() по запросу.Он не использует это внутренне, так что это просто для удобства пользователя.

query, params = SomeModel.objects.filter(foo=1).query.sql_with_params()
print(query % params)

SELECT "app_model"."id", "app_model"."some_column", "app_model"."foo" FROM "app_model" WHERE "app_model"."foo" = 1

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

Хотя вы могли бы создать свою собственную функцию для автоматического цитирования параметров и даже установить обезличенную метку класса queryset, чтобы метод __str__()вернул то, что вам нужно, я чувствую, что django-debug-toolbar - это путь, если вы делаете это регулярно.

django-debug-toolbar screenshot

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