在App Engine中的表单验证期间检查唯一性约束

时间:2013-05-08 13:18:10

标签: python google-app-engine google-cloud-datastore flask wtforms

我在App Engine中使用Flask和WTforms,尝试在其中一个字段上实现唯一性约束。问题很大,请耐心等待,我已经被困在这里很多个小时,需要你们的帮助。一个月前开始学习App Engine,Flask和WTForms。提前谢谢。

应用程序的模型“团队”如下所示:

class Team(db.Model):
    name = db.StringProperty(required=True)
    -- some other fields here --

要求:团队名称必须是唯一的。

我已按照链接

提出以下代码:

models.py:在链接中创建了一个单独的表'Unique':

class Unique(db.Model):

""" Handles uniqueness constriant on a field """

@classmethod
def unique_check(cls, form_name, field_data):
    def tx(form_name, field_data):
        key_name = "%s%s" % (form_name, field_data)
        uk = Unique.get_by_key_name(key_name)
        app.logger.debug("UK:" + str(uk))
        if uk:
            return False
        uk = Unique(key_name=key_name)
        uk.put()
        return True
    ret_val = db.run_in_transaction(tx, form_name, field_data)
    app.logger.debug("ret_val:" + str(ret_val))
    return ret_val

forms.py:我重写了__init __()和validate_on_submit()函数,其中检查了唯一性,如果它不唯一,则会将错误附加到该字段,并且验证错误将以与wtforms验证器相同的方式引发

class TeamForm(wtf.Form):

def __init__(self, *args, **kwargs):
    super(TeamForm, self).__init__(*args, **kwargs)
    if kwargs.get('edit', None):
        self.old_name = self.name.data.lower()

def validate_on_submit(self, edit=False):
    if not super(TeamForm, self).validate_on_submit():
        return False
    if edit:
        if self.old_name and self.old_name != self.name.data.lower():
            Unique.delete_entity(self.__class__.__name__, self.old_name)
            if not Unique.unique_check(self.__class__.__name__, self.name.data.lower()):
                self.name.errors.append("Value '%s' is not unique" % self.name.data)
        return False
    else:
        if not Unique.unique_check(self.__class__.__name__, self.name.data.lower()):
            self.name.errors.append("Value '%s' is not unique" % self.name.data)
            return False

    return True

    **----  Form fields declaration ----**

以上代码在插入新团队时有效。我的意思是它会正确检查唯一性。当用户编辑团队信息时,会出现问题。以下两种情况存在问题:

  • 当用户尝试提交表单时,应用程序将抛出“Not unique”错误,很明显因为“Unique”表具有此组的“key_name”。
  • 如果用户更改“团队名称”,则应用程序必须从“唯一”表中删除以前的团队名称,并且必须检查“已更改团队名称”的唯一性。我无法处理这两种情况。

我的edit_team函数如下所示:

@app.route('/team/edit/<key>', methods=['GET','POST'])
@login_required
def edit_team(key):

    k = db.Key(key)
    team = db.get(k)
    form = TeamForm(obj = team, edit=True) # to save old name, doesn't work.
    if form.validate_on_submit(edit=True): # edit=True is given only in edit function
        team.name = form.name.data
        -- others fields are updated in the similar way --
        team.put()
        return redirect(url_for('teams_list'))
    return render_template('edit_team.html', form=form)

如果我能够找到团队的“旧名称”,可以轻松解决问题,以便我可以从“唯一”表中删除它。正如您所看到的,我在TeamForm __init __()函数中保存了团队的旧名称,但是在GET(保存旧名称)期间调用__init __()并且在POST中调用(修改后的名称将被保存!!)。所以,我根本找不到旧名称,它仍然在“唯一”表中,没有人可以使用这个“旧团队名称”。

我试图尽可能多地解释,如果你想了解更多信息,请告诉我。

1 个答案:

答案 0 :(得分:1)

编辑:第一次没有正确回答你的问题。

将为GET和POST请求实例化Form对象的单独实例,因此您无法将old_name保存为self。

您需要将old_name传递给表单中的浏览器,并让浏览器在POST请求中提交old_name。

这样做的简单方法是创建一个用户看不到的隐藏表单字段,但将由POST请求提交。我对WTForms不太熟悉,但我假设您可以在GET请求处理程序中初始化old_name字段值。