Как я могу обновить определенный ключ в HStoreField в django?

У меня есть модель Django с HStoreField, и я пытаюсь обновить определенный ключ данных в этом поле. Я стараюсь не загружать модель в память, так как данных достаточно, и это будет для большого количества экземпляров объектов.

У меня есть объект Result с полем data, и я пытаюсь обновить существующий ключ, я пробовал:

Result.objects.update(data__existingkey='new_value')

Но я просто получаю FieldDoesNotExist: ResultsContainer has no field named 'data__existingkey'

Я думал, это сработает как Result.objects.filter(data__existingkey='value')работает отлично. Любые предложения будут оценены, большое спасибо

1 ответ

Первое место, которое я бы посмотрел, это django HStoreFieldдокументы. Не найдя там ничего подходящего, я бы предположил, что такая функция, если она существует, не реализована в Django.

Таким образом, мой поиск теперь нацелен на PostgreSQL. hstoreдокументы. Просматривая этот документ, я не могу найти ни одной функции, целью которой явно является обновление определенного ключа hstore. Поэтому я подробно проверяю каждую функцию, чтобы выяснить, можно ли ее использовать для этой цели.

      hstore || hstore → hstore
    Concatenates two hstores.
    'a=>b, c=>d'::hstore || 'c=>x, d=>q'::hstore → "a"=>"b", "c"=>"x", "d"=>"q"

Это бинго! С использованием ||оператор, мы можем сделать что-то вроде UPDATE "a" SET "data" = "a"."data" || hstore('existing_key=>new_value').

Теперь, поскольку это не реализовано в Django, давайте реализуем это сами:

      import re

from django.contrib.postgres.fields import HStoreField
from django.db.models import Func, Value

def hstore_def_escape(s):
    return re.sub(r'([\\"])', r'\\\1', s)

class HStore(Func)
    function = 'hstore'
    output_field = HStoreField()

    def __init__(self, expression, **kwargs):
        if isinstance(expression, dict):
            expression = Value(
                ','.join(
                   '"{}" => "{}"'.format(hstore_def_escape(k), hstore_def_escape(v))
                   for k, v in expression.items()
                )
            )
        super().__init__(expression, **kwargs)

class ConcatHStore(Func):
    arg_joiner = ' || '
    template = '%(expressions)s'
    output_field = HStoreField()

    def __init__(self, *expressions, **kwargs):
        expressions = [
            HStore(e) if isinstance(e, dict) else e
            for e in expressions
        ]
        super().__init__(*expressions, **kwargs)

Теперь вы можете сделать:

      from django.db.models import F

Result.objects.update(data=ConcatHStore(F('data'), {'existing_key': 'new_value'}))
Другие вопросы по тегам