web-dev-qa-db-fra.com

AttributeError: l'objet 'UUID' n'a pas d'attribut 'replace' lors de l'utilisation de backend-agnostic GUID type

Je veux avoir un identifiant de clé primaire de type uuid dans une base de données Postgresql à l'aide de SQLAlchemy 1.1.5, en me connectant à la base de données avec l'adaptateur pg8000. J'ai utilisé la Back-agnostic GUID Type recette de la documentation SQLAlchemy.

Lorsque je souhaite insérer dans la base de données, j'obtiens l'erreur suivante

  File ".../guid.py", line ???, in process_result_value
    return uuid.UUID(value)
  File "/usr/lib/python2.7/uuid.py", line 131, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'UUID' object has no attribute 'replace'

mon modèle ressemble à ceci

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from guid import GUID
import uuid

base = declarative_base()

class Item(base):
    __tablename__ = 'item'

    id = Column(GUID(), default=uuid.uuid4, nullable=False, unique=True, primary_key=True)
    name = Column(String)
    description = Column(String)

    def __repr__(self):
        return "<Item(name='%s', description='%s')>" % (self.name, self.description)

Ma ressource ou mon contrôleur ressemble à ceci

data = req.params
item = Item(name=data['name'], description=data['description'])

self.session.add(item)
self.session.commit()
12
The Oracle

L'adaptateur de base de données PostgreSQL pg8000 Renvoie un objet uuid.UUID() (voir leur documentation de mappage de type , et SQLAlchemy l'a transmis à la fonction TypeDecorator.process_result_value() méthode .

L'implémentation donnée dans la documentation attendait cependant une chaîne , donc cela échoue:

>>> import uuid
>>> value = uuid.uuid4()
>>> uuid.UUID(value)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python2.7/uuid.py", line 133, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'UUID' object has no attribute 'replace'

La solution rapide consiste à forcer la valeur à être une chaîne de toute façon:

def process_result_value(self, value, dialect):
    if value is None:
        return value
    else:
        return uuid.UUID(str(value))

ou vous pouvez d'abord tester le type:

def process_result_value(self, value, dialect):
    if value is None:
        return value
    else:
        if not isinstance(value, uuid.UUID):
            value = uuid.UUID(value)
        return value

J'ai soumis pull request # 4 pour corriger cela dans la documentation (depuis fusionné).

7
Martijn Pieters

Cela devrait le corriger:

id = Column(GUID(as_uuid=True), ...)

de https://bitbucket.org/zzzeek/sqlalchemy/issues/3323/in-099-uuid-columns-are-broken-with :

"Si vous souhaitez passer un objet UUID(), l'indicateur as_uuid Doit être défini sur True."

7
jrc

Cela peut être assez frustrant lors de l'utilisation d'UUID sur un système. Dans certaines conditions, il peut être difficile de contrôler si un UUID arrive sous forme de chaîne ou comme UUID brut. Pour contourner ce problème, une solution comme celle-ci pourrait fonctionner. J'ai joint les exemples du document pour m'assurer que tout le reste est toujours vrai.

# TODO: Set this up such that the normal uuid interface is available as a pass through
import uuid

class UUID(uuid.UUID):

    def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
                       int=None, version=None):

        if hex and (issubclass(type(hex), uuid.UUID) or isinstance(hex, uuid.UUID)):
            hex = str(hex)

        super(UUID, self).__init__(hex=hex, bytes=bytes, bytes_le=bytes_le, fields=fields, int=int, version=version)

print(UUID(uuid4())) # Now this works!

print(UUID('{12345678-1234-5678-1234-567812345678}'))
print(UUID('12345678123456781234567812345678'))
print(UUID('urn:uuid:12345678-1234-5678-1234-567812345678'))
print(UUID(bytes=b'\x12\x34\x56\x78' * 4)) # Python 3 requires this to be prefixed with b''. Docs appear to be mainly for Python 2
print(UUID(bytes_le=b'\x78\x56\x34\x12\x34\x12\x78\x56' +
              b'\x12\x34\x56\x78\x12\x34\x56\x78'))
print(UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)))
print(UUID(int=0x12345678123456781234567812345678))

Veuillez utiliser ceci à votre propre discrétion, ce n'est qu'un exemple.

0
Serguei Fedorov