0

I am using Flask and WTforms in App Engine, trying to implement uniqueness contraint on one of the field. The question is big, please be patient and I have been stuck here from many hours, need some help from you people. Started learning App Engine, Flask and WTForms a month ago. Thanks in advance.

Application has model 'Team' as shown below:

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

Requirement: Name of the team has to be unique.

I have followed the links

Have come up with the following code:

models.py: Created a separate table 'Unique' as given in the link:

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: I have overridden the __init__() and validate_on_submit() function in which uniqueness is checked and if it is not unique, error is attached to that field and validation error will be raised in the same way as wtforms's validators.

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 ----**

The above code works when new team is inserted.I mean it checks uniqueness properly. The problem occurs, when user edits the team information. Following two scenarios are problematic:

  • When the user tries to submit the form, application will throw "Not unique" error, it is obvious because "Unique" table has "key_name" for this team.
  • If user changes "team name", application has to delete the previous team name from the "Unique" table and has to check uniqueness for the "changed team name". I am not able to handle these two scenarios.

My edit_team function looks like this:

@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)

Problem can be easily solved if I am able to find out 'old name' of the team, so that I can delete it from the "Unique" table. As you can see I am saving old name of the team in TeamForm __init__() function, but __init__() is called during GET(old name is saved) and also in POST(modified name will get saved!!). So, I cannot find out old name at all and it remains in the "Unique" table, nobody can use this "old team name" anymore.

I tried to explain as much as possible, please let me know if you want more info.

4

1 回答 1

1

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

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

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

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

于 2013-05-08T13:51:04.427 回答