Я использую Flask и WTforms в App Engine, пытаясь реализовать ограничение уникальности в одном из полей. Вопрос большой, пожалуйста, проявите терпение, и я застрял здесь много часов, мне нужна помощь от вас, люди. Месяц назад начал изучать App Engine, Flask и WTForms. Заранее спасибо.
Приложение имеет модель «Команда», как показано ниже:
class Team(db.Model):
name = db.StringProperty(required=True)
-- some other fields here --
Требование: Название команды должно быть уникальным.
Я перешел по ссылкам
- http://www.codigomanso.com/en/2010/09/solved-anadir-claves-unicas-en-google-app-engine-en-3-lineas/
- http://squeeville.com/2009/01/30/add-a-unique-constraint-to-google-app-engine/
- http://csimms.botonomy.com/2012/07/there-are-only-two-ways-to-enforce-unique-constraints-in-google-app-engine.html
Придумали следующий код:
models.py: создана отдельная таблица "Уникальные", как указано в ссылке:
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 ----**
Приведенный выше код работает, когда вставлена новая команда, я имею в виду, что он правильно проверяет уникальность. Проблема возникает, когда пользователь редактирует информацию о команде. Следующие два сценария проблематичны:
- Когда пользователь пытается отправить форму, приложение выдаст ошибку «Не уникально», это очевидно, потому что в таблице «Уникальных» есть «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 __ (), но __init __ () вызывается во время GET (старое имя сохраняется), а также в POST (измененное имя будет сохранено !!). Итак, я вообще не могу узнать старое название, и оно остается в таблице «Уникальные», никто больше не может использовать это «старое название команды».
Я попытался объяснить как можно больше, дайте мне знать, если вам нужна дополнительная информация.