基于 Weppy/pyDal 中的另一列限制数据库插入的最佳方法?
Best way to restrict database insert based on another column in Weppy/pyDal?
如果同一用户已经拥有同名项目,我想限制特定 table 的数据库插入。
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
标签对用户来说是唯一的,所以我不希望 "name" 列被强制唯一 -> 许多用户应该能够添加相同的位置,但 "label" 中的任何内容他们想要的标签列。
NOTE: Using Weppy - I don't have enough reputation to create a new tag.
I will tag this question once I can/there is a weppy tag.
我找到了一个似乎代码太多的解决方法。需要使用 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
)
关于唯一性的复杂事情是,您不能确定仅在 Web 应用程序等并发环境中使用应用程序代码就可以尊重它。
例如,如果同一个用户将产生两个并发请求——在这种情况下可能不太可能,但你应该意识到这一点——那么应用程序代码可能会失败,因为可以在检查和其他插入之间插入具有相同值的记录。
这就是为什么你应该首先依赖数据库本身,因为 weppy 0.7 你可以使用数据库 indexes:
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)
当然你仍然可以在插入之前保留一些应用程序检查,但是由于你需要检查多个值并且自定义验证器只支持单个值(除非使用会话来检查用户),你最好使用 callbacks:
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
来自文档:
All the callbacks method should return None or False (not returning anything in python is the same of returning None) otherwise returning True will abort the current operation.
如果同一用户已经拥有同名项目,我想限制特定 table 的数据库插入。
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
标签对用户来说是唯一的,所以我不希望 "name" 列被强制唯一 -> 许多用户应该能够添加相同的位置,但 "label" 中的任何内容他们想要的标签列。
NOTE: Using Weppy - I don't have enough reputation to create a new tag. I will tag this question once I can/there is a weppy tag.
我找到了一个似乎代码太多的解决方法。需要使用 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
)
关于唯一性的复杂事情是,您不能确定仅在 Web 应用程序等并发环境中使用应用程序代码就可以尊重它。
例如,如果同一个用户将产生两个并发请求——在这种情况下可能不太可能,但你应该意识到这一点——那么应用程序代码可能会失败,因为可以在检查和其他插入之间插入具有相同值的记录。
这就是为什么你应该首先依赖数据库本身,因为 weppy 0.7 你可以使用数据库 indexes:
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)
当然你仍然可以在插入之前保留一些应用程序检查,但是由于你需要检查多个值并且自定义验证器只支持单个值(除非使用会话来检查用户),你最好使用 callbacks:
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
来自文档:
All the callbacks method should return None or False (not returning anything in python is the same of returning None) otherwise returning True will abort the current operation.