0

如果同一用户已经拥有同名的项目,我想限制特定表的数据库插入。

Table
_____________
user     | place         | label     |
--------------------------------------------------------------------------
me       | san francisco | work      |
you      | san francisco | leisure   | # This is ok because different user
me       | san francisco | leisure   | # THIS IS NOT ALLOWED - INSERT FAIL

标签对用户来说是唯一的,所以我不希望“名称”列被强制唯一 - >许多用户应该能够添加相同的位置,但在他们想要的标签列中使用任何“标签”。

注意:使用Weppy - 我没有足够的声誉来创建新标签。一旦我可以/有一个 weppy 标签,我会标记这个问题。

我找到了一个似乎代码太多的解决方法。需要使用Place().add_new()而不是内置的 pyDal 方法:

from weppy.dal import Model, Field, belongs_to


class Place(Model):
    belongs_to('user')

    name = Field() # not using `unique=True` here so others can insert same names.
    label = Field()

    def add_new(self, user_id, name, label):
        user_places = self.db(self.db.Place.user == user_id).select()
        current_names = [x.name for x in user_places]
        if name not in current_names:
            self.create(
                user=user_id,
                name=name,
                label=label
            )
4

1 回答 1

2

唯一性的复杂之处在于,您无法确定仅在 Web 应用程序这样的并发环境中使用应用程序代码就能尊重它。

例如,如果同一个用户会产生两个并发请求——在这种情况下可能不太可能,但你应该意识到这一点——那么应用程序代码可能会失败,因为可以在检查和检查之间插入具有相同值的记录另一个插入。

这就是为什么你应该首先依赖数据库本身,从 weppy 0.7 开始你可以使用数据库索引

class Place(Model):
    belongs_to('user')

    name = Field()
    label = Field()

    indexes = {
        'user_uniq_name': {
            'fields': ['user', 'name'], 'unique': True}
    }

请记住在添加索引后生成迁移。

一旦有了具有唯一约束的索引,就可以将新记录的创建包装在try-except块中:

try:
    rv = Place.create(**some_params)
except:
    # handle the error eg:
    from weppy import abort
    abort(422)

当然,您仍然可以在插入之前保留一些应用程序检查,但是由于您需要检查多个值并且自定义验证器只支持单个值(除非使用会话来检查用户),您最好使用回调

from weppy.dal import before_insert

class Place(Model):
    @before_insert
    def check_name_uniqueness(self, input_fields):
        if self.db(
            (self.user == input_fields['user']) &
            (self.name == input_fields['name'])
        ).count() > 0:
            return True
        return False

从文档中:

所有回调方法都应该返回 None 或 False(在 python 中不返回任何内容与返回 None 相同)否则返回 True 将中止当前操作。

于 2016-06-10T09:35:05.263 回答