kvesteri / wtforms-alchemy

Tools for creating wtforms from sqlalchemy models
Other
245 stars 59 forks source link

Better support for Flask? #62

Open clee704 opened 10 years ago

clee704 commented 10 years ago

When you do this:

from flask.ext.wtf import Form
from wtforms_alchemy import model_form_factory
ModelForm = model_form_factory(Form)
class UserForm(ModelForm):
    class Meta:
        model = User

You might see the following error message:

RuntimeError: application not registered on db instance and no application bound to current context

If you are following the app factory pattern.

The solution is doing some hackish things:

from wtforms_alchemy import model_form_factory, model_form_meta_factory
model_form_meta_deferred_forms = []
class ModelFormMeta(FormMeta):
    def __init__(cls, *args, **kwargs):
        super(ModelFormMeta, cls).__init__(*args, **kwargs)
        if hasattr(cls.Meta, 'model_deferred'):
            model_form_meta_deferred_forms.append(cls)
ModelForm = model_form_factory(Form,
                               meta=model_form_meta_factory(ModelFormMeta))

# in create_app()
@app.before_first_request
def create_forms():
    # Hack to avoid errors with WTForms-Alchemy
    for cls in model_form_meta_deferred_forms:
        cls.Meta.model = cls.Meta.model_deferred
        generator = cls.Meta.form_generator(cls)
        generator.create_form(cls)

and setting model_deferred instead of model on Meta. I think there should be some way to do this more easily, because if you have a non-trivial Flask app then the app factory pattern is a must.

bobwaycott commented 10 years ago

I agree better support for app-factory-based Flask apps are not as easily supported as the documentation claims. However, in case it helps others, here's a much easier approach that I have working in my own app that is far less ugly (though still disappointing)

# in project/forms/__init__.py
from flask_wtf import Form
from wtforms_alchemy import model_form_factory
from project.models import db

BaseModelForm = model_form_factory(Form)

class ModelForm(BaseModelForm):
    @classmethod
    def get_session(self):
        return db.session

# in another or same file, shouldn't matter
# if in another file, say project/forms/foo.py,
# just remember to import ModelForm
from project.models import MyModel

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        # other meta options

Everything else works as desired, as far as I can see.

tyler274 commented 9 years ago

+1

ruipacheco commented 8 years ago

Does this include the CSRF token?

katzmo commented 8 years ago

model_form_factory(Form) produces a metaclass conflict using wtforms_alchemy 0.15.0 with flask_wtforms 0.12 and wtforms 2.1 – which version would you need for this to work?

coreybrett commented 7 years ago

Given these instructions... https://wtforms-alchemy.readthedocs.io/en/latest/advanced.html#using-wtforms-alchemy-with-flask-wtf Has this issue been effectively solved now?