Django Queryset для определяемого пользователем типа Cassandra выдает ошибку типа - PullRequest
1 голос
/ 05 мая 2020

Я использую комбинацию DataStax Python Driver и Django Cassandra Engine для связи с Cassandra через приложение Django.

Вот как я определяю модель со столбцами определяемого пользователем типа (только для примера):

from cassandra.cqlengine import columns
from cassandra.cqlengine.usertype import UserType
from django_cassandra_engine.models import DjangoCassandraModel

class UserAddress(UserType)
    street = columns.Text()
    number = columns.Integer()

class User(DjangoCassandraModel):
    __table_name__ = 'users'

    user_id = columns.UUID(primary_key=True)
    name = columns.Text()
    address = columns.UserDefinedType(UserAddress)


class Meta:
    managed = False
    get_pk_field = 'user_id'

Я пытаюсь запросить эту модель с помощью следующего вызова:

User.objects.filter(user_id=user_id)

который вызывает эту ошибку:

File "/usr/local/lib/python3.8/site-packages/cassandra/cqlengine/columns.py", line 1043, in to_python

if copied_value[name] is not None or isinstance(field, BaseContainerColumn):

TypeError: tuple indices must be integers or slices, not str

Эта ошибка возникает из объявления класса UserDefinedType, в частности этой функции:

    def to_python(self, value):
    if value is None:
        return

    copied_value = deepcopy(value)
    for name, field in self.user_type._fields.items():
        if copied_value[name] is not None or isinstance(field, BaseContainerColumn):
            copied_value[name] = field.to_python(copied_value[name])

    return copied_value

Мне кажется, что Django Cassandra Engine, который включает в себя класс DjangoCassandraQuerySet, плохо сочетается с классом UserDefinedType, хотя я не уверен, почему.

До сих пор у меня не было проблем с этими библиотеками, и я нахожу это странно, что подобная операция не поддерживается. Надеюсь, я где-то пропустил конфигурацию или, по крайней мере, проблема решаема.

Спасибо за ваше время.

1 Ответ

0 голосов
/ 06 мая 2020

Спасибо этому комментарию на странице проблем Django Cassandra Engine за решение этой проблемы.

Похоже, что драйвер DataStax Python интерпретирует незарегистрированные типы как простые словари вызывая их десериализацию как серию кортежей вместо правильного словаря, что объясняет сообщение об ошибке.

Решение состоит в том, чтобы регистрировать UDT всякий раз, когда инициируется соединение. Это необходимо делать каждый раз, так как это не кажется постоянным.

Для этого добавьте этот код после объявлений класса UDT:

from cassandra.cqlengine import columns
from cassandra.cqlengine.usertype import UserType    
from django.db import connections
from cassandra.cluster import UserTypeDoesNotExist

class UserAddress(UserType)
    street = columns.Text()
    number = columns.Integer()

user_types = [ UserAddress ]
database_name = 'DjangoDBName'
keyspace = 'CassandraKeyspace'
connection = connections[database_name]

for udt in user_types:
  try:
    connection.connection.cluster.register_user_type(keyspace, udt.type_name(), udt)
  except UserTypeDoesNotExist:
    pass

В качестве альтернативы вы можете добавить этот код в файл __init__.py, если у вас есть пакет объявлений классов UDT.

Почему Django Cassandra Engine не регистрирует эти типы автоматически, я не знаю.

...