如何将WTForms自定义验证函数变量暴露给Flask视图?

时间:2017-09-18 21:45:22

标签: python python-3.x flask wtforms flask-wtforms

我有一个WTForms自定义验证函数,它返回一个包含散列的变量:

def dupe_check(self, field):
    """
    Check for duplicate images.
    """
    def get_hash():
        """
        Get hash of image.
        """
        f = field.data
        img = Image.open(f)
        imghash = imagehash.dhash(img)
        f.seek(0) 
        return imghash
    imghash = str(get_hash())
    hashcheck = str(Sights.query.filter(Sights.image_hash == imghash).first())
    if hashcheck == imghash:
        raise ValidationError('Duplicate image detected!')

class AddImageForm(FlaskForm):
    sights_image = FileField('image', validators=[FileRequired(), FileAllowed(images, 'Images only!'), dupe_check])

将位于imghash的{​​{1}}变量公开给位于forms.py的Flask视图的最佳方法是什么?

views.py应该进入WTForms HiddenField吗?我应该创建会话变量吗?我应该将imghash函数转换为类吗?

我的目标是在Flask视图期间将哈希写入数据库,但不必重新生成哈希,因为它已在验证期间创建。

2 个答案:

答案 0 :(得分:0)

在这种情况下,您可以将函数get_hash()转换为表单类的方法:

class AddImageForm(FlaskForm):
    sights_image = FileField('image', validators=[...])

    def get_hash(self):
        f = self.sights_image.data
        img = Image.open(f)
        imghash = imagehash.dhash(img)
        f.seek(0) 
        return imghash

然后在视图功能中,您只需使用表单调用它,例如:

from flask import request

@app.route('/', methods=['GET', 'POST'])
def test():
    form = AddImageForm()
    if request.method == 'POST':
        hash = form.get_hash()

答案 1 :(得分:0)

dupe_check(self, field) self中是表单实例,因此您可以将计算出的哈希值存储在表单中,并在以后的处理中使用它。

这是一个自包含的示例,请注意我创建了一个类验证器,而不是使用一个简单的方法。

from flask import Flask, request, flash, render_template_string, redirect
from flask_wtf import FlaskForm
from wtforms import ValidationError, StringField

app = Flask(__name__)

app.config['SECRET_KEY'] = '0123456789'


def get_hash(data):
    # Use data to compute hash
    image_hash = 1000000
    return image_hash


class HashValidator(object):
    def __init__(self, message=None):
        if not message:
            message = u'Duplicate image detected!'
        self.message = message

    def __call__(self, form, field):
        # Pass field data to hash function
        _img_hash = get_hash(field.data)
        # Store the hash in the form
        form.imghash = _img_hash
        # calculate if existing hash exists
        # hashcheck = str(Sights.query.filter(Sights.image_hash == _img_hash).first())
        hashcheck = 1000000
        if hashcheck == _img_hash:
            raise ValidationError(self.message)


class AddImageForm(FlaskForm):
    # sights_image = FileField('image', validators=[HashValidator()])
    # Use an Stringfield to make the sample easier
    sights_image = StringField('image', validators=[HashValidator()])


_template = '''
    {% with messages = get_flashed_messages() %}
      {% if messages %}
        <ul class=flashes>
        {% for message in messages %}
          <li>{{ message }}</li>
        {% endfor %}
        </ul>
      {% endif %}
    {% endwith %}
    <form action="/" method="POST">
        {{form.csrf_token}}
        {{form.sights_image}}
        {% if form.sights_image.errors %}
            <ul>{% for error in form.sights_image.errors %}<li>{{ error }}</li>{% endfor %}</ul>
        {% endif %}        
        <button type='submit'>Submit</button>
    </form>
'''


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        _image_form = AddImageForm()
        if _image_form.validate_on_submit():
            flash("Validated: get_hash returned {}".format(_image_form.imghash))
            return redirect('/')
        else:
            # didn't validate template will show error
            flash("Error. get_hash returned {}".format(_image_form.imghash))
            return render_template_string(_template, form=_image_form)
    else:
        _image_form = AddImageForm()
        return render_template_string(_template, form=_image_form)


if __name__ == '__main__':
    app.run(port=9876, debug=True)