使用SQLAlchemy模型的WTForms中的唯一验证器

Jér*_*eot 13 validation sqlalchemy unique wtforms

我在使用SQLALchemy管理数据库操作的应用程序中定义了一些WTForms表单.

例如,用于管理类别的表单:

class CategoryForm(Form):
    name = TextField(u'name', [validators.Required()])
Run Code Online (Sandbox Code Playgroud)

这是相应的SQLAlchemy模型:

class Category(Base):
    __tablename__= 'category'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255))

    def __repr__(self):
        return '<Category %i>'% self.id

    def __unicode__(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)

我想在表单验证上添加一个唯一约束(不在模型本身上).

阅读WTForms文档,我找到了一种简单类的方法:

class Unique(object):
    """ validator that checks field uniqueness """
    def __init__(self, model, field, message=None):
        self.model = model
        self.field = field
        if not message:
            message = u'this element already exists'
        self.message = message

    def __call__(self, form, field):         
        check = self.model.query.filter(self.field == field.data).first()
        if check:
            raise ValidationError(self.message)
Run Code Online (Sandbox Code Playgroud)

现在我可以将这个验证器添加到CategoryForm中,如下所示:

name = TextField(u'name', [validators.Required(), Unique(Category, Category.name)])
Run Code Online (Sandbox Code Playgroud)

当用户尝试添加已存在的类别时,此检查很有用\ o / 但是当用户尝试更新现有类别(不更改名称属性)时,它将无法工作.

当您想要更新现有类别时:您将使用要编辑的category属性实例化表单:

def category_update(category_id):
    """ update the given category """
    category = Category.query.get(category_id)
    form = CategoryForm(request.form, category)
Run Code Online (Sandbox Code Playgroud)

主要问题是我不知道如何访问验证器中的现有类别对象,这将允许我从查询中排除编辑的对象.

有办法吗?谢谢.

say*_*yap 10

在验证阶段,您将可以访问所有字段.所以这里的技巧是将主键传递到编辑表单中,例如

class CategoryEditForm(CategoryForm):
    id = IntegerField(widget=HiddenInput())
Run Code Online (Sandbox Code Playgroud)

然后,在Unique验证器中,将if条件更改为:

check = self.model.query.filter(self.field == field.data).first()
if 'id' in form:
    id = form.id.data
else:
    id = None
if check and (id is None or id != check.id):
Run Code Online (Sandbox Code Playgroud)

  • 它看起来好像在指望客户端(浏览器)传递正确的id值不变.是对的吗?或者,服务器代码应该在POST之后但在验证之前重置表单中的id字段? (3认同)

nsf*_*n55 5

虽然这不是一个直接的答案,但我添加它是因为这个问题与XY问题调情.WTForms的主要工作是验证表单提交的内容.虽然可以做出一个体面的案例来验证字段的唯一性可以被认为是表单验证器的责任,但是可以做出更好的情况,这是存储引擎的责任.

在我遇到这个问题的情况下,我将唯一性视为乐观情况,允许它传递表单提交并在数据库约束上失败.然后我抓住失败并将错误添加到表单中.

优点有几个.首先,它大大简化了您的WTForms代码,因为您不必编写复杂的验证方案.其次,它可以提高应用程序的性能.这是因为SELECT在尝试INSERT有效地加倍数据库流量之前,您不必调度a .

  • 打扰一下,您能否提供一个简短的代码示例,最好使用 Flask?或者,如果您知道我可以在哪里查看,可以提供一个链接吗? (2认同)