составной ключ в web2py

У меня есть таблица, определенная в web2py

db.define_table(
'pairing',
Field('user',writable=True,readable=True),
Field('uid', writable=True , readable=True)
)

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


person Ashish    schedule 13.03.2012    source источник


Ответы (2)


Это зависит от того, что вы пытаетесь сделать. По умолчанию web2py автоматически создает поле id с автоматическим увеличением, которое служит первичным ключом для каждой таблицы, и это рекомендуемый подход, когда это возможно. Если вы имеете дело с устаревшей базой данных с составными первичными ключами и не можете изменить схему, вы можете указать атрибут primarykey, хотя и с некоторыми ограничениями (как объяснено здесь):

db.define_table('pairing', 
    Field('user', writable=True, readable=True), 
    Field('uid', writable=True, readable=True),
    primarykey=['user', 'uid'])

Возможно, вместо этого вам действительно не нужен настоящий составной первичный ключ, но вам просто нужен какой-то способ гарантировать, что в таблицу будут вставлены только уникальные пары значений user/uid. В этом случае вы можете сделать это, указав правильно сконструированный IS_NOT_IN_DB валидатор для одного из двух полей:

db.define_table('pairing',
    Field('user', writable=True, readable=True),
    Field('uid', writable=True, readable=True))

db.pairing.uid.requires=IS_NOT_IN_DB(db(db.pairing.user==request.vars.user),
    'pairing.uid')

Это обеспечит уникальность uid среди набора записей, где user соответствует новому вставляемому значению user (поэтому комбинация user и uid должна быть уникальной). Обратите внимание, что валидаторы (такие как IS_NOT_IN_DB) применяются только тогда, когда значения вставляются с помощью метода SQLFORM или с использованием метода .validate_and_insert(), поэтому описанное выше не будет работать для произвольных вставок в таблицу, но в первую очередь предназначено для ввода данных пользователем.

Вы также можете использовать SQL, чтобы установить уникальное ограничение для нескольких столбцов в таблице (что вы можете сделать непосредственно в базе данных или с помощью метода web2py .executesql()). Однако даже с таким ограничением вы все равно захотите выполнить некоторую проверку ввода в своем приложении, чтобы избежать ошибок в базе данных.

person Anthony    schedule 13.03.2012
comment
У меня есть таблица, в которой я хотел бы выполнить проверку двух других полей. sh_code и sh_organization. Я попытался использовать предложенный вами код, но запись все еще вставлена. Какие-либо предложения - person Yebach; 28.01.2015
comment
Трудно сказать, не видя вашего кода. Приведенный выше подход работает с любыми двумя полями. - person Anthony; 28.01.2015

Я использую вычисляемое поле для создания/моделирования составного ключа. Взяв пример из приведенного выше вопроса, можно определить таблицу соединений следующим образом:

from md5 import md5
db.define_table( 'pairing',
                 Field('user', writable=True, readable=True),
                 Field('uid', writable=True, readable=True),
                 Field( 'user_uid_md5', 
                        length=32,
                        unique=True,
                        writable=False,
                        readable=False,
                        compute=lambda row: md5("{0}:{1}".format(row.user,row.uid)).hexdigest()))

Поле user_uid_md5 автоматически вычисляется при вставке и обновлении. Значение этого поля представляет собой md5 хэш строки, полученной из двух полей user и uid. . Это поле также помечено как unique. Таким образом, база данных обеспечивает здесь уникальность, и это работает в обход ограничения, указанного Энтони. Это также должно работать для эмуляции составных ключей с более чем двумя полями. Если вы видите какие-либо пробелы в этом подходе, пожалуйста, дайте мне знать.

Изменить: небольшое обновление способа вычисления хэша md5 для учета случая, указанного Chen Levy в комментарий ниже.

person crayzeewulf    schedule 22.01.2013
comment
На самом деле это умный подход; однако я решил использовать встроенную проверку ввода, чтобы сохранить стандарт. - person C Fairweather; 15.12.2014
comment
Это почти верно. Вы также должны учитывать случаи, когда разные комбинации user и uid приводят к одной и той же строке, например. user=1 и uid=21 против user=12 и uid=1. В этом случае оба дадут md5('121') и будут конфликтовать друг с другом. - person Chen Levy; 03.01.2016
comment
@ChenLevy, хорошая мысль. Чтобы учесть эту возможность, я немного обновил решение. Дайте мне знать, если вы видите какие-либо проблемы с этим. - person crayzeewulf; 22.02.2016
comment
На самом деле я думаю, что было бы разумнее просто использовать целое число: lambda row: ((row.user << 16) | (row.uid)). Я могу ошибаться, но всегда есть шанс, что вы получите один и тот же md5 для двух разных пар user/uid. Это предполагает, что каждое поле идентификатора меньше 16. - person bcelary; 22.04.2016