2008-10-08 24 views
36

Có cách nào để xác định cột (khóa chính) dưới dạng UUID trong SQLAlchemy nếu sử dụng PostgreSQL (Postgres) không?Làm cách nào để sử dụng UUID trong SQLAlchemy?

+0

Thật không may [Loại GUID độc lập phụ trợ] (http://docs.sqlalchemy.org/en/rel_0_9/core/custom_types.html?highlight=guid#backend-agnostic-guid-type) từ tài liệu SQLAlchemy cho các loại cột dường như không để làm việc cho các khóa chính trong các cơ sở dữ liệu SQLite. Không hẳn là đại kết như tôi mong đợi. – adamek

Trả lời

-17

Bạn có thể thử viết một custom type, ví dụ:

import sqlalchemy.types as types 

class UUID(types.TypeEngine): 
    def get_col_spec(self): 
     return "uuid" 

    def bind_processor(self, dialect): 
     def process(value): 
      return value 
     return process 

    def result_processor(self, dialect): 
     def process(value): 
      return value 
     return process 

table = Table('foo', meta, 
    Column('id', UUID(), primary_key=True), 
) 
+9

Điều này thậm chí không hoạt động, nó chỉ là một công việc cắt và dán từ ví dụ kiểu giả từ các tài liệu. Câu trả lời của Tom Willis dưới đây là tốt hơn nhiều. –

+0

Ngoài [câu trả lời của Florian] (http://stackoverflow.com/questions/183042/how-can-i-use-uuids-in-sqlalchemy/188427#188427), cũng có [mục blog này] (http: //blog.sadphaeton.com/2009/01/19/sqlalchemy-recipeuuid-column.html). Nó trông tương tự ngoại trừ nó phân lớp 'types.TypeDecorator' thay vì' types.TypeEngine'. Liệu một trong hai cách tiếp cận có một lợi thế hay bất lợi so với một trong những khác? –

+0

Không cần một 'default =? '? ví dụ. 'Cột ('id', UUID(), primary_key = Đúng, mặc định = )' – iJames

50

I wrote this và tên miền được đi nhưng đây là ruột ....

Bất kể thế nào đồng nghiệp của tôi, người thực sự quan tâm về cơ sở dữ liệu thích hợp cảm giác thiết kế về UUID và GUID được sử dụng cho các trường khóa. Tôi thường thấy tôi cần phải làm điều đó. Tôi nghĩ rằng nó có một số lợi thế hơn autoincrement mà làm cho nó có giá trị nó.

Tôi đã tinh chỉnh một loại cột UUID trong vài tháng qua và tôi nghĩ rằng cuối cùng tôi đã nhận được nó vững chắc.

from sqlalchemy import types 
from sqlalchemy.dialects.mysql.base import MSBinary 
from sqlalchemy.schema import Column 
import uuid 


class UUID(types.TypeDecorator): 
    impl = MSBinary 
    def __init__(self): 
     self.impl.length = 16 
     types.TypeDecorator.__init__(self,length=self.impl.length) 

    def process_bind_param(self,value,dialect=None): 
     if value and isinstance(value,uuid.UUID): 
      return value.bytes 
     elif value and not isinstance(value,uuid.UUID): 
      raise ValueError,'value %s is not a valid uuid.UUID' % value 
     else: 
      return None 

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

    def is_mutable(self): 
     return False 


id_column_name = "id" 

def id_column(): 
    import uuid 
    return Column(id_column_name,UUID(),primary_key=True,default=uuid.uuid4) 

# Usage 
my_table = Table('test', 
     metadata, 
     id_column(), 
     Column('parent_id', 
      UUID(), 
      ForeignKey(table_parent.c.id))) 

Tôi tin lưu trữ như nhị phân (16 byte) nên kết thúc được hiệu quả hơn so với các đại diện chuỗi (36 byte?), Và có vẻ là một số dấu hiệu cho thấy lập chỉ mục 16 byte khối nên hiệu quả hơn trong mysql so với chuỗi. Tôi sẽ không mong đợi nó sẽ tồi tệ hơn anyway.

Một bất lợi mà tôi thấy là ít nhất trong phpymyadmin, bạn không thể chỉnh sửa hồ sơ vì nó ngầm cố gắng thực hiện một số loại chuyển đổi ký tự cho "select * from table id = ..." và ở đó các vấn đề hiển thị khác.

Khác với tất cả mọi thứ dường như hoạt động tốt, và vì vậy tôi đang ném nó ra khỏi đó. Để lại một bình luận nếu bạn thấy một lỗi rõ ràng với nó. Tôi hoan nghênh mọi đề xuất để cải thiện nó.

Trừ khi tôi thiếu điều gì đó, giải pháp trên sẽ hoạt động nếu cơ sở dữ liệu bên dưới có loại UUID. Nếu không, bạn có thể sẽ gặp lỗi khi tạo bảng. Các giải pháp tôi đã đưa ra với tôi đã được nhắm mục tiêu MSSqlServer ban đầu và sau đó đã đi MySql cuối cùng, vì vậy tôi nghĩ rằng giải pháp của tôi là một chút linh hoạt hơn vì nó có vẻ làm việc tốt trên mysql và sqlite. Đã không làm phiền kiểm tra postgres được nêu ra.

+0

Điều này lẽ ra phải được chọn làm câu trả lời, tôi đoán bạn đã đăng nó sau này. –

+0

vâng tôi đã đăng nó sau khi tôi thấy giới thiệu từ câu trả lời của Jacob. –

+4

Lưu ý rằng nếu bạn đang sử dụng phiên bản 0.6 hoặc cao hơn, câu lệnh nhập MSBinary trong giải pháp của Tom nên được thay đổi thành "từ sqlalchemy.dialects.mysql.base nhập MSBinary". Nguồn: http://www.mail-archive.com/[email protected]/msg18397.html –

3

Trong trường hợp có ai quan tâm, tôi đã sử dụng Tom Willis câu trả lời, nhưng không tìm thấy hữu ích để thêm một chuỗi để chuyển đổi uuid.UUID trong phương pháp process_bind_param

class UUID(types.TypeDecorator): 
    impl = types.LargeBinary 

    def __init__(self): 
     self.impl.length = 16 
     types.TypeDecorator.__init__(self, length=self.impl.length) 

    def process_bind_param(self, value, dialect=None): 
     if value and isinstance(value, uuid.UUID): 
      return value.bytes 
     elif value and isinstance(value, basestring): 
      return uuid.UUID(value).bytes 
     elif value: 
      raise ValueError('value %s is not a valid uuid.UUId' % value) 
     else: 
      return None 

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

    def is_mutable(self): 
     return False 
3

Dưới đây là một cách tiếp cận dựa trên Backend agnostic GUID từ tài liệu SQLAlchemy, nhưng sử dụng một trường BINARY để lưu trữ UUID trong cơ sở dữ liệu không phải postgresql.

import uuid 

from sqlalchemy.types import TypeDecorator, BINARY 
from sqlalchemy.dialects.postgresql import UUID as psqlUUID 

class UUID(TypeDecorator): 
    """Platform-independent GUID type. 

    Uses Postgresql's UUID type, otherwise uses 
    BINARY(16), to store UUID. 

    """ 
    impl = BINARY 

    def load_dialect_impl(self, dialect): 
     if dialect.name == 'postgresql': 
      return dialect.type_descriptor(psqlUUID()) 
     else: 
      return dialect.type_descriptor(BINARY(16)) 

    def process_bind_param(self, value, dialect): 
     if value is None: 
      return value 
     else: 
      if not isinstance(value, uuid.UUID): 
       if isinstance(value, bytes): 
        value = uuid.UUID(bytes=value) 
       elif isinstance(value, int): 
        value = uuid.UUID(int=value) 
       elif isinstance(value, str): 
        value = uuid.UUID(value) 
     if dialect.name == 'postgresql': 
      return str(value) 
     else: 
      return value.bytes 

    def process_result_value(self, value, dialect): 
     if value is None: 
      return value 
     if dialect.name == 'postgresql': 
      return uuid.UUID(value) 
     else: 
      return uuid.UUID(bytes=value) 
+0

Cách sử dụng này sẽ là gì? – codeninja

7

Nếu bạn hài lòng với một 'String' cột có giá trị UUID, ở đây đi một giải pháp đơn giản:

def generate_uuid(): 
    return str(uuid.uuid4()) 

class MyTable(Base): 
    __tablename__ = 'my_table' 

    uuid = Column(String, name="uuid", primary_key=True, default=generate_uuid) 
Các vấn đề liên quan