Code Monkey home page Code Monkey logo

wtforms-alchemy's Introduction

wtforms-alchemy's People

Contributors

adamrt avatar adarshk7 avatar alexluke avatar arthurbarros avatar ash211 avatar cisko3000 avatar coltonprovias avatar coyotevz avatar crast avatar duncanbetts avatar fayazkhan avatar fedexpress avatar gergelypolonkai avatar jacobsvante avatar javex avatar krak3n avatar kvesteri avatar oskarihiltunen avatar quantus avatar superosku avatar tvuotila avatar vesauimonen avatar westurner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wtforms-alchemy's Issues

Custom field class

Example syntax:

field = sa.Column(sa.Unicode(255), info={'form_field_class': MyCustomField})

Add 'filters' and 'widget' support to the generator

Can we please add 'filters' and 'widget' support to the 'create_field' function in generator.py

I believe adding the following to the 'create_field' function would do the trick.

        if 'filters' in column.info:
            kwargs['filters'] = column.info['filters']

        if 'widget' in column.info:
            kwargs['widget'] = column.info['widget']

Explain how to get the model instance from a ModelForm

Hi, is there existing a way to get the model instance from a ModelForm? Actually in my code I have some code repetitions due to building of the model based on the form fields.

View is the model (Base class)
self refers to the current form (ModelForm)

def get_view(self):
        view = View()
        view.title = self.title.data
        view.link_name = self.link_name.data
        view.datasource = self.datasource.data
        view.buttontext = self.buttontext.data
        view.reload_intervall = self.reload_intervall.data
        view.layout_number_columns = self.layout_number_columns.data
        return view

I looked in the docs and there is no section that talks about this, is this because we have to do this manually every time? If yes, it will be nice if we could just get the model instance like this: form.model or with another simple way.

Edit: another way a little simpler could be to iterate on the data attribute and use getattr function to get the field. It's useful if you have dynamic fields.

Example:

(get_filters is a form function)

def get_filters(self):
        filters = ViewFilters()
        for col, value in self.filters.data.iteritems():
            setattr(filters, col, value)

        return filters

Regards

Unique validators when editing a row

The unique field validator section of the documentation talks about the normal case especially for a new record. But I get some trouble when I attempt to edit a row that have unique column. Indeed, the validator will verify unicity of unique field and will return a validation error that is in fact a conflict with itself.

I've put a workaround on my code that you can see here: but it is not very convinient. https://github.com/smlacombe/sageo/blob/master/app/controllers/edit_view.py#L65

Is there anything I've miss?

Thanks

Date fields with not null and defaults

Currently date / datetime / time fields with nullable=False and some default are marked as optional by default. In this scenario these fields should be marked as required.

SelectField forms not generating "selected" option attr

This might be a problem of not knowing well the framework, but here it is:
I create a form out of a model:

ModelForm = model_form_factory(Form)
class DnsUpdateForm(ModelForm):
    class Meta:
        model = Dnsrec
        only = ('rectype', 'recsrc', 'recdst', 'ttl', 'id')
        rectype = SelectField(choices=((u'a', A), (u'cname', CNAME)), validators=[DataRequired()])
# (some code removed for clarity)

If I have a dnsrec orm object loaded from the database and create a form that is populated from it:

vform = DnsUpdateForm(obj=dnsrec)

then vform.rectype renders a HTML element without the actual rectype value being chosen via a "select" attribute. The reason is that the default coerce function is unicode() and sqlalchemy_utils.types.choice.Choice().unicode() returns the second from the pair of strings for each choice and that is assigned to vform.rectype.data. Thus matching this with the actual value never wins as they differ in case. Making them fully equal is a no solution for me. Providing a coerce function to SelectField() does not seem to have an effect either. Hacking sqlalchemy_utils.types.choice.Choice().unicode() to return six.text_type(self.code) did solve the issue (but does not seem to be the proper way to do it :)) Please help sorting this out, thanks! Yassen

ModelFieldDict?

I was trying ModelFieldList(FormField(...)), and accidentally used it on a relation that was actually an attribute_mapped_collection, and thus a type of dict, not a list. This failed (it probably took keys instead of model instances when building, and couldn't insert to MappedCollection populating.

There's a "test_model_field_dict.py" from Dec 2013 in tests, but it is commented out, and imports a ModelFieldDict class that doesn't exist. Was support started for mapped collection relationships, and is it something still on the radar?

Field name generated when column remapped to different property name?

Is there an issue when a declarative model specifies an explicit column name in its definition, different from the database column name? For instance:

class User(Base):
  propertyName = sa.Column('columnName', sa.Integer)

class UserForm(ModelForm)
  class Meta:
    model = User

The database column "columnName" is mapped to the property "propertyName" in the model. However, your FormGenerator.create_fields seems to create fields from the "name" property of the Column. In the case above, the form gets a field called "columnName", even though the model has "propertyName", and things like populate_obj or form creation may fail?

Would it be better to use value "attribute.key" in create_fields for the field name, which would contain "propertyName" in this case, and honor the remapping being done in the model?

Version in docs/conf.py needs updating

The "version" and "release" (and "copyright") fields in docs/conf.py haven't been updated in awhile - they still show 0.5.4 and 2012. This affects the the readthedocs.org documentation, at least.

Better support for Flask?

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.

Not working in python 2.6.6

collections.OrderedDict was added in python 2.7 and thus an error is thrown when wtforms_alchemy tries to import it

...
  File "/path/to/project/forms.py", line 10, in <module>
    from wtforms_alchemy import model_form_factory
  File "/usr/local/lib/python2.6/dist-packages/wtforms_alchemy/__init__.py", line 23, in <module>
    from .generator import FormGenerator
  File "/usr/local/lib/python2.6/dist-packages/wtforms_alchemy/generator.py", line 2, in <module>
    from collections import OrderedDict
ImportError: cannot import name OrderedDict

wtforms_alchemy.UnknownTypeException: VARCHAR(255)

Here's the offending model field:

note = sa.Column(sa.String(255), nullable=True)

Using Postgres, that apparently amounts to a VARCHAR, which is not found in FormGenerator.TYPE_MAP, yielding this error:

File "[...]/local/lib/python2.7/site-packages/wtforms_alchemy/__init__.py", line 323, in get_field_class
    raise UnknownTypeException(column.type)
wtforms_alchemy.UnknownTypeException: VARCHAR(255)

csrf protection in wtforms-alchemy

Hello,

I am using wtforms-alchemy with csrf enabled in my flask app.
When rendering the form I got an error:

UndefinedError: 'MyForm object' has no attribute 'hidden_tag'

Is there any workaround for this issue?

Thanks!

create a wtfform from model using only select rows

I have a website that has multiple user created forms. I track all inputs/fields (over 800 now!) using the following model which associates each field to a particular form using a foreign key relationship. Is it possible to auto-generate a wftform using only select rows from a model (form_field.query.filter_by(form_id = id)? If not this may be a nice feature to have.

class form_field(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(64))
    description = db.Column(db.String(256))
    form_id = db.Column(db.Integer, db.ForeignKey('form.id'))
    form = db.relationship('form', backref = db.backref('form_fields', lazy='dynamic'))}}

Delcaration order of fields lost

If I loop through the fields of a ModelForm, they seem to come out in an indeterminate order. I believe sqlalchemy and wtforms generally preserve declaration order in basic cases, and the scrambling comes from ModelForm.

FormGenerator seems to convert a list of model attributes into a set in create_form and validate_attributes, presumably to eliminate potential duplicates. I'd guess the fact that sets are unordered makes the later loop through it come out in an arbitrary order.

Would it be possible to replace the set with an OrderedDict? It could be filled with _sa_class_manager.iteritems() instead of values(), validate_attribute could return an (attr_name, attr) pair, and create_fields could loop through values(). I think this would then preserve the declaration ordering, or the order of "only".

It isn't a big deal, but I'm lazy and tend to just dump out forms with a simple looping render_template() during development, or for undemanding production. It would be nice if the output order wasn't a lottery! If I get some free time I'll try this out to see if it works.

Regression of Issue 38 - not using model's property name for field name

I can't seem to reopen issue 38, but it looks like the fix for it added in 0.7.15 has been lost or regressed, probably at or before 0.8.3?

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer
from wtforms import Form
from wtforms_alchemy import model_form_factory

ModelBase = declarative_base()
class TestModel(ModelBase):
    __tablename__ = 'TestTable'
    id = Column(Integer, primary_key=True)
    newName = Column('oldname', Integer)

AbstractForm = model_form_factory(Form)
class F(AbstractForm):
    class Meta:
        model = TestModel

form = F()
for f in form:
    print f.name, f

if form.oldname:
    print "Regression of Issue #38: Column name used instead of property name"

prints out html code when appending entry to ModelFieldList

When calling append_entry() to a ModelFieldList of an empty form with no existing data, it is giving the html code of the input element of that field.
screen shot 2014-01-08 at 4 58 05 pm

We are modeling the form like this:
ModelForm = model_form_factory(Form)

class VariableForm(ModelForm):
class Meta:
model = Variable

class ServerForm(ModelForm):
class Meta:
model = Server

variables = ModelFieldList(FormField(VariableForm, widget=TableWidget(with_table_tag=False)), min_entries=1)
create_server = SubmitField()
add_variable = SubmitField('Add Variable')
delete_variable = SubmitField('Remove Variable')

And in the views.py:
server = Server()
variable = Variable()
variable_form = VariableForm(obj=variable)
form = ServerForm(request.form, obj=server)
...
form.variables.append_entry(variable_form)

Incorrect validator used for non-nullable fields.

The DataRequired validator is not the correct validator to use for a non-nullable field. Note the warning in wtforms.validators:

Unless a very specific reason exists, we
recommend using the :class:`InputRequired` instead.

That said, even the InputRequired validators does not quite fit the bill. That is because a non-nullable field even accepts an empty string โ€“ which is not valid according to InputRequired.

What's needed is a validator that simply asserts that there is an input โ€“ hence not None.

wtforms_alchemy.exc.UnknownTypeException

wtforms_alchemy.exc.UnknownTypeException
UnknownTypeException: Unknown type 'BIT' for column 'RandomBitField'

Hello ...

I am getting this error when trying to generate a form from a sql alchemy model "autoloaded" from an MS SQL table. The field is .. as described .. a BIT field.

Any way to exclude the field or supplement the conversion process?
Thanks

Display customizing error messages

In WTForms I can display customizing error messages by adding message in Validators but in WTForms-Alchemy when use ModelForm as below ( I don't know where can set customizing error message )

class MyModel(Base):
    __tablename__ = 'user'
    id = Column(BigInteger, primary_key=True)
    email = Column(EmailType, unique=True, nullable = False,
               info={'label': 'Email'})
    name = Column(Unicode(length=45), nullable = False,
              info={'label': 'Name'})
    password = Column(String(length=64),
                  info={'label': 'Your Password',
                        'widget': widgets.PasswordInput()})

class UserForm(ModelForm):
    class Meta:
        model = MyModel

    @staticmethod
    def get_session():
        return DBSession

0.11 pypi release incompatible with wtforms-components pypi 0.9 release

These are currently the latest versions on the index, but installing and using them gives:

  File ".../venv/lib/python2.7/site-packages/wtforms_alchemy/__init__.py", line 9, in <module>
   ImportError: cannot import name NumberRangeField

It does not appear that wtforms_components exports NumberRangeField. The current master of wtforms-alchemy does not import it, so the pypi release for this project probably just needs to be updated.

Can't install from PyPI

Can't pip install this package, although it exists at http://pypi.python.org/pypi/wtforms-alchemy. i think that's because there's no zip/tar there.

$ pip install wtforms-alchemy
Downloading/unpacking wtforms-alchemy
  Could not find any downloads that satisfy the requirement wtforms-alchemy
No distributions at all found for wtforms-alchemy

Required() validation not working for checkbox/Boolean via 'info' definition

I am finding that Required() validation is not working for checkbox/Boolean when I define the Required() validator in the SQLA class 'info' dict.

But it does work when I define the validator as an override in the ModelForm class.

Am I doing something wrong ?

Please find below a working example that demonstrates the issue.
You should be able to run the example after setting up the virtualenv with mkvirtualenv.

#
# mkvirtualenv wa_bool_test -i Flask-SQLAlchemy==0.16 -i Flask-WTF==0.8.3 -i WTForms-Alchemy==0.6.0
#
# python wtforms_alchemy_boolean_test.py
#
from wtforms_alchemy import ModelForm
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.wtf import BooleanField, Required, SubmitField
from flask import Flask, request, redirect, url_for, render_template_string

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
db = SQLAlchemy(app)


class Table(db.Model):

    __tablename__ = 'sometable'

    id = db.Column(
        db.Integer(),
        primary_key=True,
        autoincrement=True
    )

    tick_me = db.Column(
        db.Boolean(),
        info={
            'label': 'Go on, Tick Me',
            'validators': [Required()]
        },
        nullable=False
    )


class FormOne(ModelForm):

    class Meta:
        model = Table

    submit = SubmitField('Submit')


class FormTwo(ModelForm):

    class Meta:
        model = Table

    tick_me = BooleanField(
        'Go on, Tick Me',
        validators=[Required()]
    )

    submit = SubmitField('Submit')


template_home = """
<!doctype html>
<html>
<head>
<title>Boolean Required Test Home</title>
</head>
<body>
<h2>Boolean Required() Test</h2>
<a href="{{ url_for('formone') }}">Info dict validator</a><br><br>
<a href="{{ url_for('formtwo') }}">Override validator</a>
</body>
</html>
"""

template_form = """
<!doctype html>
<html>
<head>
<title>{{ title }} validator method</title>
</head>
{% block body %}
<h2>{{ title }} validator method</h2>
<form action='{{ path }}' method=post>
{% if form.errors %}
  <b><font color="ff0000">The form contains errors : </font></b>
  {{ form.errors }}<br><br>
{% endif %}
<tr><td>{{ form.tick_me.label }}</td><td>{{ form.tick_me() }}</td></tr>
<br><br>
{{ form.submit() }}
<br><br>
<a href="{{ url_for('home') }}">Home</a>
{% endblock %}
</html>
"""


@app.route('/', methods=['GET'])
def home():
    return render_template_string(template_home)


@app.route('/formone', methods=['GET', 'POST'])
def formone():
    form = FormOne(request.form)
    if request.method == 'POST':
        if form.validate():
            return redirect(url_for("home"))
    return render_template_string(template_form, form=form,
                                  title='Info dict', path=url_for('formone'))


@app.route('/formtwo', methods=['GET', 'POST'])
def formtwo():
    form = FormTwo(request.form)
    if request.method == 'POST':
        if form.validate():
            return redirect(url_for("home"))
    return render_template_string(template_form, form=form,
                                  title='Override', path=url_for('formtwo'))

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Tracking fields that aren't rendered

From what I can tell, when WTForms creates a form and the passed "formdata" is not empty, any fields not present in formdata will get initialized to empty or default values, even if a passed "obj=" parameter has them. Understandable, since things like HTML checkboxes don't get POSTed and have to be assumed off if not present.

But for a ModelForm, if you include a model's field but don't render it in the form you send out, on the return POST that field obviously won't be present and will be blanked out in the form. If you then use populate_obj() on the model instance from the db, you'll accidentally wipe out the existing value?

Obviously fields should be rendered (or hidden) in these forms, but it seems a bit fragile when making changes, like adding a model field to the form but forgetting to render it out in the template. Would it be feasible to patch into the base WTForms Field.call() method, and keep track of which fields have been _call_ed (and implicitly rendered)? ModelForm could then have an "unconsumed()" method which would return a list of fields not called, and debug code could check and throw a fit if a the rendering routine doesn't render everything out.

Forcing SelectField for nullable int columns

I tried the following code but it seems the coerce function is int all the time. It always ends up getting ValueError: invalid literal for int() with base 10: ''.

year = db.Column(db.Integer, info=dict(
    coerce=lambda x: int(x) if x else None,
    choices=[
        ('', '- Select year -'),
        (2014, 2014),
        (2013, 2013),
        ...
    ]))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.