【问题标题】:Can't set uuid primary field in postgresql table flask-sqlalchemy无法在 postgresql 表 flask-sqlalchemy 中设置 uuid 主字段
【发布时间】:2019-06-07 04:30:25
【问题描述】:

我正在创建一个包含多个表的后端,其中用户 ID 作为主字段,在 postgresql 数据库中是 UUID 类型。但我收到以下错误:

Traceback (most recent call last):
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1179, in _execute_context
    context = constructor(dialect, self, conn, *args)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 743, in _init_compiled
    for key in compiled_params
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 743, in <genexpr>
    for key in compiled_params
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 487, in process
    value = _python_UUID(value)
  File "/usr/lib64/python3.7/uuid.py", line 157, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'UUID' object has no attribute 'replace'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/flask/app.py", line 1832, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/flask/app.py", line 1818, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/flask_restful/__init__.py", line 458, in wrapper
    resp = resource(*args, **kwargs)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/flask_restful/__init__.py", line 573, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/mnt/home/Programming/Projects/Social Network/Server/src/new_user.py", line 17, in post
    self.database_helper(args)
  File "/mnt/home/Programming/Projects/Social Network/Server/src/new_user.py", line 26, in database_helper
    db.session.commit()
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/scoping.py", line 162, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1026, in commit
    self.transaction.commit()
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 493, in commit
    self._prepare_impl()
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 472, in _prepare_impl
    self.session.flush()
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2458, in flush
    self._flush(objects)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2596, in _flush
    transaction.rollback(_capture_exception=True)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 68, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 129, in reraise
    raise value
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2556, in _flush
    flush_context.execute()
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/unitofwork.py", line 422, in execute
    rec.execute(self)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/unitofwork.py", line 589, in execute
    uow,
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/persistence.py", line 245, in save_obj
    insert,
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/orm/persistence.py", line 1066, in _emit_insert_statements
    c = cached_connections[connection].execute(statement, multiparams)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 988, in execute
    return meth(self, multiparams, params)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 287, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1107, in _execute_clauseelement
    distilled_params,
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
    e, util.text_type(statement), parameters, None, None
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1466, in _handle_dbapi_exception
    util.raise_from_cause(sqlalchemy_exception, exc_info)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 383, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 128, in reraise
    raise value.with_traceback(tb)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1179, in _execute_context
    context = constructor(dialect, self, conn, *args)
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 743, in _init_compiled
    for key in compiled_params
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 743, in <genexpr>
    for key in compiled_params
  File "/home/ayushs/.local/share/virtualenvs/Server-D_x4HQZH/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 487, in process
    value = _python_UUID(value)
  File "/usr/lib64/python3.7/uuid.py", line 157, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
sqlalchemy.exc.StatementError: (builtins.AttributeError) 'UUID' object has no attribute 'replace'

这是我的模型:

from database.shared_db import db
from sqlalchemy.dialects import postgresql
from database.shared_bycrypt import bcrypt

class AuthenticationModel(db.Model):
    user_id = db.Column('UserId', postgresql.UUID, primary_key = True)
    email = db.Column('Email', postgresql.TEXT, unique = False, nullable=False)
    phone_no = db.Column('PhoneNo', postgresql.TEXT, unique = False, nullable=False)
    password = db.Column('Password', postgresql.TEXT, unique = False, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.user_id

    @property
    def password_raw(self):
        raise AttributeError('password not readable')
    @password_raw.setter
    def password_raw(self, password):
        self.password = bcrypt.generate_password_hash(password)

    def verify_password(self, password):
        return bcrypt.check_password_hash(self.password, password)

这是我的数据库辅助函数:

def database_helper(self, args):
        id = uuid4()
        userAuth = AuthenticationModel(user_id=id, email=args['email'], phone_no=args['phone_no'], password_raw=args['password'])
        userInfo = PersonalInfoModel(user_id=id, first_name=args['first_name'], last_name=args['last_name'], dob=args['dob'])
        db.session.add(userAuth)
        db.session.add(userInfo)
        db.session.commit()

我发现了许多自动生成 UUID 字段的示例。但是,如果我想跨多个数据库创建一些用户,我该怎么做?因为我认为即使我为其中一个表自动生成用户 ID,我也需要能够将用户 ID 传递给其他表。还是我应该简单地使用文本字段?

【问题讨论】:

    标签: python postgresql sqlalchemy


    【解决方案1】:

    uuid4() 正在生成一个 UUID 实例。

    您想为user_id 字段传递一个字符串。将其转换为字符串

    user_id = str(uuid4())
    

    如果您想传递 UUID 实例并将它们返回到结果中,您应该将架构中的 user_id 字段更新为:

    user_id = db.Column('UserId', postgresql.UUID(as_uuid=True), primary_key=True)
    

    【讨论】:

    • id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) 我不建议对 UUID 进行字符串处理,特别是如果您打算利用该列与另一个表建立外键关系...
    • @EricMilliot-Martinez 这不是重点。字符串可用于与另一个表的外键关系。你在说什么?
    • 在您的回答@Oluwafemi Sule 中,user_id = str(uuid4()) 正是我所说的重点。我强烈建议人们不要这样做。为什么?因为我刚刚解决了一个问题所在的错误,因为假设user_id 也被用作不同表中的外键。我在提交该新表的多个实例(记录)时遇到问题,并且必须重新启动应用程序才能将另一个对象保存到数据库中。我停止串接 uuid,如 default=uuid.uuid4 所示,保存问题已解决。
    • 从此页面:docs.sqlalchemy.org/en/14/dialects/postgresql.htmlas_uuid=False¶ – if True, values will be interpreted as Python uuid objects, converting to/from string via the DBAPI.
    • 如果您打算使用字符串作为 UUID,那么您的默认工厂应该返回字符串而不是 UUID 对象,以避免类型不匹配。在这个发布的问题中,OP 声明了没有默认工厂且类型为postgresql.UUID 的字段。在这种情况下,他们必须为该字段传递一个字符串值。如果他们用as_uuid=True 声明了该字段,则传递一个UUID 对象就可以了。 Here are some tests 澄清了这种行为。
    猜你喜欢
    • 1970-01-01
    • 2021-06-14
    • 2021-12-23
    • 2021-06-14
    • 2016-12-09
    • 1970-01-01
    • 2017-12-30
    • 2021-06-14
    • 2014-12-02
    相关资源
    最近更新 更多