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()
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é).
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'indicateuras_uuid
Doit être défini sur True."
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.