Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FileRequired validator? #13

Open
mathause opened this issue Mar 15, 2023 · 2 comments
Open

Add FileRequired validator? #13

mathause opened this issue Mar 15, 2023 · 2 comments

Comments

@mathause
Copy link

mathause commented Mar 15, 2023

The DataRequired does not properly work for FileField, because it returns a starlette.datastructures.UploadFile and is thus not empty (even if no file is uploaded). So it might be worthwhile to add a FileRequired validator. You can repro this with:

from jinja2 import Template
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import PlainTextResponse, HTMLResponse
from starlette_wtf import StarletteForm, CSRFProtectMiddleware, csrf_protect
from wtforms import FileField
from wtforms.validators	import DataRequired


class MyForm(StarletteForm):
    photo = FileField(validators=[DataRequired()])


template = Template('''
<html>
  <body>
    <form method="post" novalidate enctype="multipart/form-data">
      {{ form.csrf_token }}
      <div>
        {{ form.photo() }}
        {% if form.photo.errors -%}
        <span>{{ form.photo.errors[0] }}</span>
        {%- endif %}
      </div>
      <button type="submit">Submit</button>
    </form>
  </body>
</html>
''')


app = Starlette(middleware=[
    Middleware(SessionMiddleware, secret_key='***REPLACEME1***'),
    Middleware(CSRFProtectMiddleware, csrf_secret='***REPLACEME2***')
])


@app.route('/', methods=['GET', 'POST'])
@csrf_protect
async def index(request):
    """GET|POST /: form handler
    """
    form = await MyForm.from_formdata(request)

    if await form.validate_on_submit():


        print(form.photo.data)
        # print(form.photo.size)

        return PlainTextResponse(f'Data Size: {form.photo.data.size}')


    html = template.render(form=form)
    return HTMLResponse(html)
@mathause
Copy link
Author

mathause commented Mar 15, 2023

The validator could look like this (modeled after the DataRequired validator):

from wtforms.validators import StopValidation

class FileRequired:
    def __init__(self, message=None):
        self.message = message
        self.field_flags = {"required": True}

    def __call__(self, form, field):
        if field.data and field.data.size > 0:
            return
        if self.message is None:
            message = field.gettext("This field is required.")
        else:
            message = self.message

        field.errors[:] = []
        raise StopValidation(message)

class MyForm(StarletteForm):
    photo = FileField(validators=[FileRequired()])

@amorey
Copy link
Member

amorey commented Mar 15, 2023

Thanks, this looks very useful! Would you be interested in submitting a PR to add file validators to starlette-wtf like flask-wtf's: https://github.com/wtforms/flask-wtf/blob/main/src/flask_wtf/file.py?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants