2014-02-10 5 views
1

Это может быть относительно простой вопрос для ответа. Но я включу весь свой код только для полноты.Конфигурирование MySQL для генерации значений первичного ключа

Я генерирую альфа-числовые первичные ключи для своих таблиц MySQL, используя класс, найденный here. Тем не менее, когда я загрузить строку в базу данных, я получаю эту ошибку:

FlushError: Instance <User at 0x1d47110> has a NULL identity key. If this is an auto-generated value, check that the database table allows generation of new primary key values, and that the mapped Column object is configured to expect these generated values. Ensure also that this flush() is not occurring at an inappropriate time, such as within a load() event. 

Итак, вот код, когда я использую GUID код из SQLAlchemy источника:

User.py

from app import db 
from app.custom_db.GUID import GUID 

class User(db.Model): 
    __tablename__ = 'users' 
    id = db.Column(GUID(), primary_key = True) 
    name = db.Column(db.String(40), unique = True) 
    email_stub = db.Column(db.String(30), unique = True) 

    def __init__(self, name, email_stub): 
    self.name = name 
    self.email_stub = email_stub 

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

Когда я просто использую db.Integer, он отлично работает. Но, как я уже сказал, я хочу, чтобы пользовательские альфа-цифровые uuid4() первичные ключи. Как я могу заставить мою базу данных MySQL не жаловаться, когда я это делаю?

+0

Просто нужно добавить, что использование UUID в качестве первичного ключа не является хорошей идеей. InnoDB использует первичный ключ в каждом вторичном ключе и добавляет 16 байт для каждого ключа. Лучше всего использовать целое число как первичный ключ (и использовать AUTO_INCREMENT) и сделать GUID вторичным ключом. Кроме того, что еще более важно, сохраните GUID как BINARY (16). Это может быть не важно с 1000 пользователями, но с миллионом это будет. – geertjanvdk

+0

Действительно? Является ли автоинкрементное целое безопасным? Я чувствую, что это облегчило бы представлять других пользователей, если бы вы могли угадать их первичный ключ. –

+1

Вы никогда не должны раскрывать свой первичный ключ, если он не случайный. Вы открываете случайный GUID (как шестнадцатеричный) и используете первичный ключ внутри. Вы сэкономите много сетевого трафика и пространства, идущего от ~ 16-32 байт до 4 или 8 байтов (INT/BIGINT). – geertjanvdk

ответ

3

необходимо перенести default generation function на первичный ключ. Здесь мы также будем использовать упрощенную версию backend-agnostic GUID type примера, так что мы видим реальные UUID,:

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 
import uuid 

Base = declarative_base() 

class GUID(TypeDecorator): 
    impl = String(32) 

    def process_bind_param(self, value, dialect): 
     if value is not None: 
      return "%.32x" % value 
     else: 
      return MNone 

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

class User(Base): 
    __tablename__ = 'users' 
    id = Column(GUID(), primary_key=True, default=uuid.uuid4) 
    name = Column(String(40), unique=True) 

e = create_engine("mysql://scott:[email protected]/test", echo=True) 
Base.metadata.drop_all(e) # just for testing here 
Base.metadata.create_all(e) 

s = Session(e) 

s.add_all([User(name='u1'), User(name='u2'), User(name='u3')]) 
s.commit() 

for guid in s.query(User.id): 
    print(guid) 
+0

И это проверит, чтобы убедиться, что uuid уникален? Что произойдет, если это не так. Выбросит ли ошибка или просто попробует еще раз с uuid? –

+3

не будет вызывать ошибки, потому что, когда вы получите свой первый неповторимый uuid, земля упадет на солнце, и компьютер не будет работать в любом случае. см. http://en.wikipedia.org/wiki/UUID#Random_UUID_probability_of_duplicates – zzzeek

Смежные вопросы