A flexible forms validation and rendering library for Python.

Overview

WTForms

WTForms is a flexible forms validation and rendering library for Python web development. It can work with whatever web framework and template engine you choose. It supports data validation, CSRF protection, internationalization (I18N), and more. There are various community libraries that provide closer integration with popular frameworks.

Installation

Install and update using pip:

pip install -U WTForms

Third-Party Library Integrations

WTForms is designed to work with any web framework and template engine. There are a number of community-provided libraries that make integrating with frameworks even better.

  • Flask-WTF integrates with the Flask framework. It can automatically load data from the request, uses Flask-Babel to translate based on user-selected locale, provides full-application CSRF, and more.
  • WTForms-Alchemy provides rich support for generating forms from SQLAlchemy models, including an expanded set of fields and validators.
  • WTForms-SQLAlchemy provides ORM-backed fields and form generation from SQLAlchemy models.
  • WTForms-AppEngine provides ORM-backed fields and form generation from AppEnding db/ndb schema
  • WTForms-Django provides ORM-backed fields and form generation from Django models, as well as integration with Django's I18N support.
  • Starlette-WTF integrates with Starlette and the FastAPI framework, based on the features of Flask-WTF.

Links

Comments
  • Booleanfield broken in 2.2

    Booleanfield broken in 2.2

    Booleanfield's checked state got broken in 2.2

    If an object's member variable is True, the generated field's data will be False.

    # user.verified is True
    
    class UserEditForm(Form):
        verified = BooleanField('verified')
    
    form = UserEditForm(obj=user)
    print(user.verified) # True
    print(form.verified.data) # False
    
    opened by hyperknot 16
  • General way to pass extra attributes to Field

    General way to pass extra attributes to Field

    According to http://www.w3.org/TR/html-markup/syntax.html#syntax-attributes attribute name allows almost all characters, including - (dash)

    I'm trying to create an <input> tag with attribute data-toggle to work with Flat-UI's css definition, but unfortunately current design of Field.__call__ doesn't allow such attribute names.

    opened by yegle 16
  • Urgent: Please release 2.1.1 that fixes error with SQLAlchemy 1.2

    Urgent: Please release 2.1.1 that fixes error with SQLAlchemy 1.2

    https://github.com/wtforms/wtforms/blob/2.1/wtforms/ext/sqlalchemy/fields.py#L188-L190

    In 1.2 identity_key returns a third item which is not really relevant here but breaks the list unpacking. I would suggest this change to support both 1.1 and 1.2:

    -cls, key = identity_key(instance=obj)
    +key = identity_key(instance=obj)[1]
    

    For reference, here's the relevant part of the traceback with WTForms 2.1 and SQLAlchemy 1.2:

      File ".../wtforms/ext/sqlalchemy/fields.py", line 100, in _get_object_list
        self._object_list = list((text_type(get_pk(obj)), obj) for obj in query)
      File ".../wtforms/ext/sqlalchemy/fields.py", line 100, in <genexpr>
        self._object_list = list((text_type(get_pk(obj)), obj) for obj in query)
      File ".../wtforms/ext/sqlalchemy/fields.py", line 189, in get_pk_from_identity
        cls, key = identity_key(instance=obj)
    ValueError: too many values to unpack
    
    opened by ThiefMaster 14
  • InputRequired doesn't accept 0 as valid

    InputRequired doesn't accept 0 as valid

    Hello,

    I have a form that looks like this,

    class VoteForm(Form):
        article_id = IntegerField('article_id', [validators.DataRequired()])
        vote_type  = IntegerField('vote_type', [validators.InputRequired(), validators.NumberRange(min = 0, max = 1)])
    

    and create the form with,

    form = VoteForm(data = request.json_body)
    

    request.json_body is the dictionary {u'article_id': 1, u'vote_type': 0}.

    I would expect that the value 0 is fine with InputRequired but it seems it is not.

    opened by Grieverheart 14
  • Add support for multiple file input

    Add support for multiple file input

    Took a similar approach to SelectField and SelectMultipleField. The FileInput widget now takes a multiple argument, and there are two fields FileField and MultipleFileField.

    FileField is no longer based on StringField, since it's only a coincidence that the data is a string. I updated the docs to clarify that extensions might change what data is passed to this field (see Flask-WTF for example).

    If no data is passed to the field, its data is None rather than the empty string. There was no test for this before, so I figured it was ok to break this. None makes more sense for "no file was uploaded". The multiple field will have an empty list for no data.

    FileInput always sets value to False so that it is not rendered. Browsers won't honor the value of a file input for security reasons anyway. FileField._value returns False as well, to be consistent if the widget it changed.

    An alternate implementation could use one FileField with a multiple argument as well. I'm willing to implement that instead if it sounds better.

    This patch contains #280 (call process_formdata if formdata is empty) since testing this ran into that issue. Merging this after that, or just closing that, should both work in git.

    opened by davidism 12
  • Non boolean values for field_flags

    Non boolean values for field_flags

    This allows to specify a function returning a dictionary for field_flags. This allows validators to set flags which are supported directly in HTML for client side validation, such as minlength, which then get rendered appropriately by the widgets supporting that attribute.

    Fixes #406

    enhancement 
    opened by Sohalt 11
  • fields: keep entries order in errors list 2: son of fields: keep entries order in errors list

    fields: keep entries order in errors list 2: son of fields: keep entries order in errors list

    (This PR is a resubmission of #258.)

    Three facets two consider:

    1. New behaviour adds None for empty errors. Maybe it should add [] so users can avoid the extra is not None?
    2. To localize errors, it's only necessary to add Nones up to the latest error, e.g. ['a', '', 'a'] -> [None, <errors>] instead of [None, <errors>, None]. It might be more convenient to have the error list the same length as the data.
    3. If no errors, the old behaviour (errors == []) is kept. Ditto above on convenience.
    opened by valtron 10
  • Error when validating FileField in Pyramid

    Error when validating FileField in Pyramid

    Hi,

    I am trying to add "required" validation on FileField in Pyramid.

    When I don't provide any file and submit the form, it works fine by providing "The field is required" message. However, when I actually choose a file and submit the form, I am getting errors. (Please see stacktrace at the end)

    The following is the minimal code to reproduce the error.

    Pyramid view and Form:

    class File(Form):
        file = FileField('Upload a file', validators=[required()])
    
    
    @view_config(route_name='upload', renderer='templates/file.pt')
    def file_view(request):
        file = File(request.POST)
        if request.method == 'POST' and file.validate():
            return render_to_response('templates/success.pt',
                                      {},
                                      request=request)
        return {'form': file}
    

    And chameleon template:

    <!DOCTYPE HTML>
    <html lang="en">
    <body>
        <form method="POST" enctype="multipart/form-data" accept-charset="utf-8">
            <span tal:repeat="field form">
                ${field.label} ${field()}
                <span class="error" tal:repeat="error field.errors">
                    <span>${error}</span>
                </span>
                <br><br>
            </span>
            <input type="submit" value="submit">
        </form>
    </body>
    </html>
    

    The error I am getting is the following:

        if request.method == 'POST' and file.validate():
      File "/home/james/venv/lib/python3.5/site-packages/wtforms/form.py", line 310, in validate
        return super(Form, self).validate(extra)
      File "/home/james/venv/lib/python3.5/site-packages/wtforms/form.py", line 152, in validate
        if not field.validate(self, extra):
      File "/home/james/venv/lib/python3.5/site-packages/wtforms/fields/core.py", line 204, in validate
        stop_validation = self._run_validation_chain(form, chain)
      File "/home/james/venv/lib/python3.5/site-packages/wtforms/fields/core.py", line 224, in _run_validation_chain
        validator(form, self)
      File "/home/james/venv/lib/python3.5/site-packages/wtforms/validators.py", line 201, in __call__
        if not field.data or isinstance(field.data, string_types) and not field.data.strip():
      File "/usr/lib/python3.5/cgi.py", line 661, in __bool__
        raise TypeError("Cannot be converted to bool.")
    TypeError: Cannot be converted to bool.
    

    Any help is appreciated!

    opened by J20S 10
  • Rework the WTForms logo

    Rework the WTForms logo

    We have this logo for the wtforms group:

    logo

    And we have this logo for the documentation:

    logo

    Both are in poor resolution. We should probably make them svgs.

    Any suggestions or help is welcomed!

    enhancement 
    opened by azmeuk 9
  • DataRequired and InputRequired do not add required attribute to RadioField objects

    DataRequired and InputRequired do not add required attribute to RadioField objects

    When adding a DataRequired or InputRequired validator to a RadioField, the required attribute of the input tag.

    Here's the function I wrote that reveals the problem:

        @bp.route('/<string:slug>/survey', methods=['GET', 'POST'])
        def survey(slug):
            survey = Survey.query.filter_by(slug=slug).first_or_404()
            questions = survey.questions
            for question in questions:
                if question.category == 'word':
                    field = StringField(question.question, validators=[InputRequired()])
                elif question.category == 'likert':
                    choices = [('1', 'Strongly Agree'),
                               ('2', 'Agree'),
                               ('3', 'Neutral'),
                               ('4', 'Disagree'),
                               ('5', 'Strongly Disagree')]
                    field = RadioField(question.question, choices=choices, validators=[InputRequired()])
                setattr(FlaskForm, str(question.id), field)
            setattr(FlaskForm, 'submit', SubmitField('Submit'))
            form = FlaskForm()
            if form.validate_on_submit():
                response = Response(survey=survey)
                db.session.add(response)
                for question in questions:
                    answer = Answer(question=question, response=response)
                    field = getattr(form, str(question.id))
                    if question.category == 'word':
                        answer.answer = field.data
                    elif question.category == 'likert':
                        choices = {'1': 'Strongly Agree',
                                   '2': 'Agree',
                                   '3': 'Neutral',
                                   '4': 'Disagree',
                                   '5': 'Strongly Disagree'}
                        answer.answer = choices[field.data]
                    db.session.add(answer)
                db.session.commit()
                with open('app/static/ty.txt', 'r') as f:
                    ty = [x.strip() for x in f.readlines()]
                return render_template('ty.html', ty=ty)
            return render_template('survey.html', form=form, questions=questions)
    

    I understand there might be other issues with the above (such as me being informed I should subclass FlaskForm).

    The above function gives the following input tag for a StringField:

        <input class="form-control" id="4" name="4" required="" type="text" value="">
    

    This is the input tag for a RadioField:

        <input id="1-0" name="1" type="radio" value="1">
    

    While in the browser's debugger, if I edit the above to <input id="1-0" name="1" type="radio" value="1" required="">, the radio button requires a selection.

    bug 
    opened by chivalry 9
  • fix python 3 compatibility

    fix python 3 compatibility

    Hi,

    I have just updated my WTForms requirements from 2.1 to 2.2.1 but it triggers what looks like a python 3 compatibility issue (I reproduced the issue both with python 3.7.2 and 3.6.8).

    Here is a traceback:

      File "/opt/workspace/burp-ui/burpui/routes.py", line 479, in login
        form = LoginForm(request.form)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/wtforms/form.py", line 212, in __call__
        return type.__call__(cls, *args, **kwargs)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/flask_wtf/form.py", line 88, in __init__
        super(FlaskForm, self).__init__(formdata=formdata, **kwargs)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/wtforms/form.py", line 272, in __init__
        super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/wtforms/form.py", line 52, in __init__
        field = meta.bind_field(self, unbound_field, options)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/wtforms/meta.py", line 27, in bind_field
        return unbound_field.bind(form=form, **options)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/wtforms/fields/core.py", line 353, in bind
        return self.field_class(*self.args, **kw)
      File "/root/.pyenv/versions/3.6.8/envs/bui-3.6.8/lib/python3.6/site-packages/wtforms/fields/core.py", line 451, in __init__
        self.choices = copy(choices)
      File "/root/.pyenv/versions/3.6.8/lib/python3.6/copy.py", line 96, in copy
        rv = reductor(4)
    TypeError: can't pickle dict_items objects
    

    My guess is this was introduced by #286

    I'm also not sure whereas the default should be None or [] (since copy(None) => None)

    I also don't know if I should make this PR against the 2.2 maintenance branch or not.

    opened by ziirish 9
  • SelectField defaults choices to None, not [] as documented.

    SelectField defaults choices to None, not [] as documented.

    Actual Behavior

    from wtforms import Form, SelectField
    
    class MyForm(Form):
        foo = SelectField()
    
    
    def test_construct():
        form = MyForm()
        assert form.foo.choices == []
    

    When you run the test, it fails because form.foo.choices is None, not []:

    ./src/dyk_tools/test_select_form.py::test_construct Failed: [undefined]assert None == []
     +  where None = <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0>.choices
     +    where <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0> = <dyk_tools.test_select_form.MyForm object at 0x7fac5325fa90>.foo
    def test_construct():
            form = MyForm()
    >       assert form.foo.choices == []
    E       assert None == []
    E        +  where None = <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0>.choices
    E        +    where <wtforms.fields.choices.SelectField object at 0x7fac5325fbe0> = <dyk_tools.test_select_form.MyForm object at 0x7fac5325fa90>.foo
    

    Expected Behavior

    form.foo.choices should be [] as is documented at https://wtforms.readthedocs.io/en/3.0.x/fields/#wtforms.fields.SelectField

    As a more practical example with this Flask code:

    class TemplateForm(Form):
        name = SelectField(validate_choice=False)
    
    def home_page():
        form = TemplateForm(request.form)
        if request.method == "POST" and form.validate():
            return redirect(url_for("display", template_name=form.name.data))
        form.name.choices = get_pending_nominations()
        return render_template("home_page.html", form=form)
    

    It fails on the POST branch with:

    Traceback (most recent call last):
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 2548, in __call__
        return self.wsgi_app(environ, start_response)
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 2528, in wsgi_app
        response = self.handle_exception(e)
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 2525, in wsgi_app
        response = self.full_dispatch_request()
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 1822, in full_dispatch_request
        rv = self.handle_user_exception(e)
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 1820, in full_dispatch_request
        rv = self.dispatch_request()
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/flask/app.py", line 1796, in dispatch_request
        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
      File "/Users/roy/dev/dyk-tools/src/dyk_tools/flask_app/app.py", line 14, in home_page
        if request.method == "POST" and form.validate():
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/form.py", line 329, in validate
        return super().validate(extra)
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/form.py", line 146, in validate
        if not field.validate(self, extra):
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/fields/core.py", line 231, in validate
        self.pre_validate(form)
      File "/Users/roy/dev/dyk-tools/venv/lib/python3.9/site-packages/wtforms/fields/choices.py", line 136, in pre_validate
        raise TypeError(self.gettext("Choices cannot be None."))
    TypeError: Choices cannot be None.
    

    Explicitly setting choices to []:

        name = SelectField(validate_choice=False, choices=[])
    

    makes things work as expected.

    Environment

    • Python version: 3.9.13
    • wtforms version: 3.0.1
    opened by roysmith 0
  • Add shorter format datetime-local defaults

    Add shorter format datetime-local defaults

    Describe the issue you are attempting to fix

    This issue was previously raised in #450.

    The HTML standard for datetime-local inputs set the default step attribute to 60, meaning that the lowest denomination of input can be expressed in minutes, not seconds.

    https://html.spec.whatwg.org/#local-date-and-time-state-(type=datetime-local)

    The step attribute is expressed in seconds. The step scale factor is 1000 (which converts the seconds to milliseconds, as used in the other algorithms). The default step is 60 seconds.

    In such cases, it seems that common browser behaviour is to then send the input value, without any seconds, on form submission, in the format -

    2022-11-02T12:23
    

    The current default of WTForms is to validate against two possible date formats, both that require seconds -

    def __init__(self, *args, **kwargs):
            kwargs.setdefault("format", ["%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S"])
    

    If seconds are not found, the validation will fail -

    Not a valid datetime value.
    

    Current fixes

    This issue can be fixed by adding the correct format to a DateTimeLocalField() instance -

    example_date_time = DateTimeLocalField('Example datetime', format="%Y-%m-%dT%H:%M")
    

    or by change input step size to allow seconds (in HTML)**

    <input type="datetime-local" step="1">
    

    Proposal

    Very simple PR to bring WTForms in line with the default behaviour of some browsers, by adding two formats (without seconds) to the default formats of DateTimeLocalField.

        def __init__(self, *args, **kwargs):
            kwargs.setdefault("format", ["%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M", "%Y-%m-%dT%H:%M"])
    
    opened by russellfinlay 5
  • for Regexp validator set html input tag 'pattern' attribute

    for Regexp validator set html input tag 'pattern' attribute

    for Regexp validator set html input tag 'pattern' attribute (used if novalidate not set on a form)

    Similar to the Length validator that sets the html input attributes minlength and maxlength I found it useful to have this for regex patterns as well. One advantage of using the browser is to get the message translated already (even tough here it is a bit generic, since it only says input needs to match the requested format and does not tell about the format itself)

    added some basic test ... not sure if that is accepted this way?

    opened by lefty01 1
  • Update .readthedocs.yaml to re-enable pdf/epub download

    Update .readthedocs.yaml to re-enable pdf/epub download

    In the RTD download section only old doc is available for download. I tried to create RTD project pointing to this repo, with epub and pdf enabled, but the build process yield no downloadable doc, until I fork this repo and specified the output format in the yaml config. If the official RTD project already have epub/pdf build enabled, it probably needs this change, otherwise please reject this.

    opened by zcattacz 0
  • Missing a way to disable csrf for testing

    Missing a way to disable csrf for testing

    I found no way to turn off csrf if testing with pytest. Am I missing something? Functional tests and app in production actually produce CSRF, thats all good. however I wan't to disable this for testing because all validates fail in testing as testing can't handle csrf. (this might be a "workaround" for all you interested - I wanted to go the "quick" way and disable csrf in testing and here I am 3 hours later).

    Following meta.rst and csrf.rst my Class looks like this. I use Flask so I return session.

    app/form/form.py

    ...
    from app.config import Config
    class BaseForm(ModelForm):
        class Meta:
            csrf = True
            csrf_class = SessionCSRF
            csrf_secret = Config.CSRF_SECRET_KEY
    
            @property
            def csrf_context(self):
                return session
    

    app/__init__.py Inititiation:

    import os
    from flask import Flask
    from app.config import Config
    
    def create_app(test_config=None):
    
        app = Flask(__name__, instance_relative_config=True)
    
        app.config.from_object(Config)
    
        if test_config:
            app.config.from_mapping(test_config)
    
    ....#blueprints and blabla
    

    config.py for the staging and production apps

    from dotenv import dotenv_values
    env = dotenv_values(".env")
    class Config:
    
        SECRET_KEY = env.get("SECRET_KEY")
        CSRF_SECRET_KEY = env.get("CSRF_SECRET_KEY").encode()
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        SQLALCHEMY_DATABASE_URI = "sqlite:///../instance/database.sqlite"
    

    conftest.py for pytest, here you see the apparently legacy config commands which should stop CSRF according to half of the population of the internet

    import pytest
    
    from app import create_app
    from app.db import db
    
    test_config = {
        "SECRET_KEY": "TEST_CONFIG",
        "TESTING": True,
        "SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:",
        "WTF_CSRF_ENABLED": False,
        "WTF_CSRF_CHECK_DEFAULT": False,
        "WTF_CSRF_SECRET_KEY":None,
        "CSRF_SECRET_KEY":None,
    }
    
    @pytest.fixture(scope="session")
    def test_app():
    
        test_app = create_app(test_config=test_config)
        with test_app.app_context():
    
            db.create_all()
            yield test_app
            db.drop_all()
    

    None of these apparently legacy (?) config parameters for the app factory of flask switch off csrf globally for testing - forms expect csrf tokens to be validated True

    Is there no way to disable CSRF at app initiation, what am I missing?

    wtforms==3.0.1 ; python_version >= "3.8" and python_version < "4.0"

    opened by iameru 1
  • Python minimal version is wrong in FAQ / 3.0.1 changelog not published

    Python minimal version is wrong in FAQ / 3.0.1 changelog not published

    FAQ Claims compatibility with python 3.6 : https://wtforms.readthedocs.io/en/3.0.x/faq/#what-versions-of-python-are-supported

    Changelog does not exists for 3.0.1 : https://wtforms.readthedocs.io/en/3.0.x/changes/#version-3-0-0

    opened by JoKoT3 2
Releases(3.0.1)
  • 3.0.1(Dec 23, 2021)

  • 3.0.0(Nov 7, 2021)

    Released 2021-11-07

    • Fixed fields.RadioField validators. #477 #615
    • fields.FormField.populate_obj always calls setattr #675
    • WTForms has a new logo. #569 #689
    • Fixed fields.RadioField render_kw rendering. #490 #628 #688
    • Support for optgroups in fields.SelectField and fields.SelectMultipleField. #656 #667
    • Minor documentation fix. #701
    • Custom separators for fields.FieldList. #681 #694
    • fields.DateTimeField, fields.DateField and fields.TimeField support time formats that removes leading zeros. #703
    • Refactoring: split fields/core.py and fields/simple.py #710
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0a1(Nov 23, 2020)

    • Drop support for Python < 3.6. #554
    • fields.StringField sets data to None when form data is empty and an initial value was not provided. Although it previously set an empty string, None is consistent with the behavior of other fields. #355
    • Specified version of Babel required for setup to avoid errors. #430
    • Replaced use of getattr/setattr with regular variable access. #482
    • ValueError raised by a validator are handled like regular exceptions. Validators need to raise validators.ValidationError or validators.StopValidation to make a validation fail. #445
    • fields.SelectField, fields.SelectMultipleField and fields.RadioField choices parameter can be a callable. #608
    • Choices shortcut for fields.core.SelectMultipleField. #603 #605
    • Forms can have form-level errors. #55 #595
    • Implemented fields.core.MonthField. #530 #593
    • Filters can be inline. form.BaseForm.process takes a extra_filters parameter. #128 #592
    • Fields can be passed the name argument to use a HTML name different than their Python name. #205, #601
    • Render attribute names like for_ and class_ are normalized consistently so later values override those specified earlier. #449, #596
    • Flags can take non-boolean values. #406 #467
    • Widgets are HTML5 by default. #594 #614
    • Fixed a bug when the fields.core.SelectField choices are list of strings. #598
    • Error messages standardization. #613 #620 #626 #627
    • fields.core.SelectMultipleField validate_choice bugfix. #606 #642
    • Fixed SelectMultipleField validation when using choices list shortcut. #612 #661
    Source code(tar.gz)
    Source code(zip)
  • 2.3.3(Jul 30, 2020)

  • 2.3.2(Jul 30, 2020)

  • 2.3.1(Apr 22, 2020)

  • 2.3.0(Apr 21, 2020)

    • Changes: https://wtforms.readthedocs.io/en/2.3.x/changes/#version-2-3-0

    It's been a while! Thanks to the new maintainers who helped get the new release ready.

    2.3.x will be the last version to support Python 2. Version 3.0 will support Python >= 3.6.

    Source code(tar.gz)
    Source code(zip)
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Dec 31, 2022
A set of high-level abstractions for Django forms

django-formtools Django's "formtools" is a set of high-level abstractions for Django forms. Currently for form previews and multi-step forms. This cod

Jazzband 619 Dec 23, 2022
A CBV to handle multiple forms in one view

django-shapeshifter A common problem in Django is how to have a view, especially a class-based view that can display and process multiple forms at onc

Kenneth Love 167 Nov 26, 2022
Tweak the form field rendering in templates, not in python-level form definitions. CSS classes and HTML attributes can be altered.

django-widget-tweaks Tweak the form field rendering in templates, not in python-level form definitions. Altering CSS classes and HTML attributes is su

Jazzband 1.8k Jan 6, 2023
Full control of form rendering in the templates.

django-floppyforms Full control of form rendering in the templates. Authors: Gregor Müllegger and many many contributors Original creator: Bruno Renié

Jazzband 811 Dec 1, 2022
A Python HTML form library.

Deform Introduction Use cases Installation Example Status Projects using Deform Community and links Introduction Deform is a Python form library for g

Pylons Project 391 Jan 3, 2023
FlaskBB is a Forum Software written in Python using the micro framework Flask.

FlaskBB is a Forum Software written in Python using the micro framework Flask.

FlaskBB 2.3k Dec 30, 2022
Easy and free contact form on your HTML page. No backend or JS required.

Easy and free contact form on your HTML page. No backend or JS required. ?? ??

0xDEADF00D 8 Dec 16, 2022
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Jan 5, 2023
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Dec 31, 2022
The best way to have DRY Django forms. The app provides a tag and filter that lets you quickly render forms in a div format while providing an enormous amount of capability to configure and control the rendered HTML.

django-crispy-forms The best way to have Django DRY forms. Build programmatic reusable layouts out of components, having full control of the rendered

null 4.6k Jan 7, 2023
App and Python library for parsing, writing, and validation of the STAND013 file format.

python-stand013 python-stand013 is a Python app and library for parsing, writing, and validation of the STAND013 file format. Features The following i

Oda 3 Nov 9, 2022
Lightweight data validation and adaptation Python library.

Valideer Lightweight data validation and adaptation library for Python. At a Glance: Supports both validation (check if a value is valid) and adaptati

Podio 258 Nov 22, 2022
Lightweight, extensible data validation library for Python

Cerberus Cerberus is a lightweight and extensible data validation library for Python. >>> v = Validator({'name': {'type': 'string'}}) >>> v.validate({

eve 2.9k Dec 27, 2022
CONTRIBUTIONS ONLY: Voluptuous, despite the name, is a Python data validation library.

CONTRIBUTIONS ONLY What does this mean? I do not have time to fix issues myself. The only way fixes or new features will be added is by people submitt

Alec Thomas 1.8k Dec 31, 2022
A simple, fast, extensible python library for data validation.

Validr A simple, fast, extensible python library for data validation. Simple and readable schema 10X faster than jsonschema, 40X faster than schematic

kk 209 Sep 19, 2022
Prithivida 690 Jan 4, 2023
Aplicação GUI feita em Python para estudos de cadastro (forms).

Cadastro de DEVs GUI ?? A ideia original veio do repositório do https://github.com/PedroTomazeti nomeado 'Projetos-Independentes-HTML-CSS' Nele há um

Yago Goltara 3 Aug 15, 2021
A bot written in python that send prefilled Google Forms. It supports multithreading for faster execution time.

GoogleFormsBot https://flassy.xyz https://github.com/Shawey/GoogleFormsBot Requirements: os (Default) ast (Default) threading (Default) configparser (

Shawey 1 Jul 10, 2022