formalchemy / formalchemy Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
FormAlchemy eliminates boilerplate by autogenerating HTML input fields from a given model. FormAlchemy will try to figure out what kind of HTML code should be returned by introspecting the model's properties and generate ready-to-use HTML code that will fit the developer's application. Of course, FormAlchemy can't figure out everything, i.e, the developer might want to display only a few columns from the given model. Thus, FormAlchemy is also highly customizable. Please visit the FormAlchemy's homepage for documentation and more information: http://docs.formalchemy.org/ You can subscribe to FormAlchemy's mailing list: http://groups.google.com/group/formalchemy
The docs include an example of multi-field in-field validation. The linked example suggests using field.parent.<otherfield>.value
as follows:
>>> def passwd2_validator(value, field):
... if field.parent.passwd1.value != value:
... raise validators.ValidationError('Password do not match')
This will not work as expected in cases where an empty value for <otherfield>
is submitted and the previous / persisted value of model.<otherfield>
is not None. In these cases <otherfield>.value
will return the previous value in the model instead of the submitted value in the request.
Although this does not affect this particular example - because "password confirmation" fields are typically not persisted - the example may be misleading to users who are looking to implement multi-field validation.
One workaround is to use _deserialize() instead:
>>> def passwd2_validator(value, field):
... if field.parent.passwd1._deserialize() != value:
... raise validators.ValidationError('Password do not match')
Or better yet, users should be directed to implement multi-field validation as a global (fieldset-level) validator that is run after all independent field-level validation is complete.
... coming soon ?
WebOb 1.2 has removed the definition of UnicodeMultiDict, which forms.py depends on.
https://groups.google.com/forum/#!topic/formalchemy/kPqqYFc2Oxs
This issue makes formalchemy totally unusable.
If the prefix is set to 0 it will not be applied due to line 148 in fields.py:
prefix = self.field.parent._prefix or ''
The _validate_method of Fielset raises KeyError when some fields are missing in submitted data, whereas we would expect it to simply return false.
For example, if you have the following model :
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String, unique=True, nullable=False)
and the following submission validation code :
if fs.validate():
fs.sync()
# Other stuff here
If you submit the following data, validate returns true :
{'email': '[email protected]'}
but if you submit the following data, validate raises a KeyError exception :
{'dumbass': '[email protected]'}
KeyError: u"User--email not found in SimpleMultiDict([('User--dumbass', u'[email protected]')])"
In this case, we would simply expect validate to return false and populate the errors dictionary accordingly.
The rendered examples and links in http://docs.formalchemy.org/formalchemy.html are missing.
TranslationString mod only takes dictionary-based %-formatting, so the following lines (validators.py line 146-151):
def f(value, field=None):
if len(value) < min_:
raise ValidationError(_('Value must be at least %d characters long') % min_)
if max_ is not None and len(value) > max_:
raise ValidationError(_('Value must be no more than %d characters long') % max_)
return f
Should be:
def f(value, field=None):
if len(value) < min_:
raise ValidationError(_('Value must be at least %(min) characters long') % {'min': min_})
if max_ is not None and len(value) > max_:
raise ValidationError(_('Value must be no more than %(max) characters long') % {'max': max_})
return f
I was under the impression issue 11 would include hybrid_properties but I cannot make them work. Consider the following example where gender is a synonym for _gender:
from formalchemy import Column
from formalchemy.forms import FieldSet
from sqlalchemy import Table, Unicode, Integer, create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import sessionmaker
session = sessionmaker()
Session = session()
engine = create_engine('postgresql://usr:pass@localhost/db', echo=True)
Session.configure(bind=engine)
m = MetaData()
m.bind = engine
base = declarative_base(metadata=m)
class Test(base):
__tablename__ = "example"
id = Column(Integer, autoincrement=True, primary_key=True)
name = Column(Unicode(100), nullable=False)
_gender = Column(Unicode(1), nullable=False, default=True)
@hybrid_property
def gender(self):
return self._gender
@gender.setter
def gender(self, value):
if value.upper() not in ('F', 'M'):
raise(Exception(u'Gender must be F or M'))
else:
self._gender = value.upper()
m.create_all()
fs1 = FieldSet(Test())
fs1.configure(include=[fs1.name, fs1.gender])
fs1.render()
When I execute it, I'm getting:
Traceback (most recent call last):
File "<ipython-input-3-37113d7b6e1e>", line 1, in <module>
import property_fa as f
File "property_fa.py", line 35, in <module>
fs1.configure(include=[fs1.name, fs1.gender])
File "/home/mariano/Code/example/env/lib/python2.7/site-packages/FormAlchemy-1.4.1-py2.7.egg/formalchemy/forms.py", line 773, in __getattr__
raise AttributeError(attrname)
AttributeError: gender
If I use _gender as the included field, of course it works however it bypasses my property control.
TIA,
Mariano
So if you're like me, and needed to update an ancient webapp that uses FormAlchemy, but were frustrated by the lack of a release that fixes the WebHelpers incompatibility which causes an error related to not being able to use lists/tuples for options, here's how to fix that:
git clone [email protected]:FormAlchemy/formalchemy.git
cd formalchemy
python setup.py sdist
cd dist
You're now in a folder with a file called FormAlchemy-1.6.dev0.tar.gz
. Put that file somewhere online (a S3 bucket works great), and then add that URL to your requirements file. You may also need to update from WebHelpers==1.3
to WebHelpers2==2.0
, but I'm not 100% certain about that.
It seems that the SQLAlchemy 0.9 does neither provide Function nor _Function in package sqlalchemy.sql.expression. I meet import error when running FormAlchemy 1.4.3 with SQLAlchemy 0.9:
...... File "/opt/webenv/local/lib/python2.7/site-packages/FormAlchemy-1.4.3-py2.7.egg/formalchemy/fields.py", line 1944, in render return AbstractField.render(self) File "/opt/webenv/local/lib/python2.7/site-packages/FormAlchemy-1.4.3-py2.7.egg/formalchemy/fields.py", line 1586, in render return self.renderer.render(**opts) File "/opt/webenv/local/lib/python2.7/site-packages/FormAlchemy-1.4.3-py2.7.egg/formalchemy/fields.py", line 446, in render return h.text_field(self.name, value=self.value, **kwargs) File "/opt/webenv/local/lib/python2.7/site-packages/FormAlchemy-1.4.3-py2.7.egg/formalchemy/fields.py", line 177, in value value = self.field.model_value File "/opt/webenv/local/lib/python2.7/site-packages/FormAlchemy-1.4.3-py2.7.egg/formalchemy/fields.py", line 1875, in model_value return self._pkify(self.raw_value) File "/opt/webenv/local/lib/python2.7/site-packages/FormAlchemy-1.4.3-py2.7.egg/formalchemy/fields.py", line 1894, in raw_value from sqlalchemy.sql.expression import _Function as Function ImportError: cannot import name _Function - Expression: "fs.render()" - Filename: ... .jquery-0.9.5-py2.7.egg/fa/jquery/templates/admin/new.pt - Location: (line 6: col 36) - Source:^^^^^^^^^^^ - Expression: "field.render()" - Filename: ... ry-0.9.5-py2.7.egg/fa/jquery/templates/forms/fieldset.pt - Location: (line 21: col 32) - Source: tal:content="structure field.render()" /> ^^^^^^^^^^^^^^ - Arguments: repeat: {...} (0) renderer_name: pyramid_formalchemy:templates/forms/fieldset.pt localizer: F_: renderer_info: focus_rendered: True fieldset: _: fatypes: request: req: field: html: context: view:
Try to submit this form without filling in text t
input:
from formalchemy import FieldSet, types
from formalchemy.fields import Field
from datetime import datetime
class MyClass(object):
td = Field(type=types.DateTime, value=datetime.now())
t = Field().required()
MyFS = FieldSet(MyClass)
fs = MyFS.bind(model=MyClass, data={
'MyClass--td__year': '2011',
'MyClass--td__month': '12',
'MyClass--td__day': '12',
'MyClass--td__hour': '17',
'MyClass--td__minute': '28',
'MyClass--td__second': '49',
'MyClass--t': ""
})
fs.validate()
print(fs.render())
print(fs.td.value)
What happens to me is, for example, datetime December 12 2011 17:28:49
becomes February 02 2011 07:08:09
so selected options change from 12 to 2, 17 to 7 and so on.
This happens to me also with mapped SA classes in different forms using formalchemy 1.3.5, 1.3.6 and 1.3.7
The website formalchemy.org and docs.formalchemy.org are offline. The domain hasn't expired, but it appears that the resource records no longer exist.
In fields.py
from sqlalchemy.exceptions import InvalidRequestError # 0.4 support
raises excpetion
File "E:\eXchange\Python27\lib\site-packages\formalchemy-1.3.9-py2.7.egg\formalchemy\fields.py", line 18, in <module>
from sqlalchemy.exceptions import InvalidRequestError # 0.4 support
ImportError: No module named exceptions
It worked for SqlAlchemy 6.7.
If I change it to from sqlalchemy.exc import InvalidRequestError # 0.4 support
, it works.
formalchemy version is 1.39
title says it all
I believe there is an issue in forms.py, lines 614 and 638 - (FA1.3.7).
If I try to add a field for a relation, the name and the key differ, and the .index call fails.
Thanks
Marco
I can't even begin to imagine what this thing is supposed to be doing, but what it's actually doing is destroying long <select>
lists.
Here's the code for the function:
def _sanitize_select_options(options):
if isinstance(options, (list, tuple)):
if _only_contains_leaves(options) and len(options) >= 2:
return (options[1], options[0])
else:
return [_sanitize_select_options(option) for option in options]
return options
Notice that if the options
variable is a list of length >= 2, with elements which are not also lists (e.g. a list of several strings), it converts options
into (options[1], options[0])
.
Why in the world does it do this? This results in every list of 2+ options being incorrectly rendered into a <select>
.
I'm no expert when it comes to recursive functions, but it appears that (besides destroying every option list) this function doesn't do anything. When I made what appeared to be the most sensible fix the remove the bug, I realized that the function stopped having any effect.
I'd suggest either removing _sanitize_select_options(), or re-writing it to do what it was originally intended to do, whatever that was. Until that time, though, FormAlchemy v1.4.3 is completely worthless. I was forced to downgrade to v1.4.2.
Is this project moribund/dead? The documentation site http://doc.formalchemy.org is no longer operating.
The FieldSet
constructor accepts a request
kwarg. If it is supplied, then self._request
will be non-None.
FieldSet.bind()
also accepts a request object as a kwarg with a default of None
. If a request is not supplied to bind()
, then bind()
will overwrite mr._request
with None
:
def bind(self, model=None, session=None, data=None, request=None,
with_prefix=True):
# ...
mr = object.__new__(self.__class__)
mr.__dict__ = dict(self.__dict__)
# ...
mr._request = request
return mr
bind()
should not set mr._request
if request
is None
or falsy.
Just checked out from pypi:
TypeError
TypeError: lists/tuples are no longer allowed as elements in the 'options' arg: ('MM', 'Month')
Traceback (most recent call last)
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid_debugtoolbar/panels/performance.py", line 57, in resource_timer_handler
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid/tweens.py", line 21, in excview_tween
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid_tm/init.py", line 92, in tm_tween
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid_tm/init.py", line 73, in tm_tween
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid/router.py", line 163, in handle_request
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid/config/views.py", line 245, in _secured_view
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid/config/views.py", line 355, in rendered_view
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/pyramid/config/views.py", line 501, in _requestonly_view
File "/export/home/usname/myapp/app/views/view_subpage.py", line 784, in subpage_audit_trail
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/tables.py", line 140, in render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/templates.py", line 70, in call
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/templates.py", line 104, in render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/mako/template.py", line 452, in render_unicode
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/mako/runtime.py", line 803, in _render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/mako/runtime.py", line 835, in _render_context
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/mako/runtime.py", line 860, in _exec_template
File "memory:0x7f54e19fb190", line 38, in render_body
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/fields.py", line 1931, in render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/fields.py", line 1554, in render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/fields.py", line 652, in render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/fields.py", line 593, in _render
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/formalchemy/helpers.py", line 180, in select
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/webhelpers2/html/tags.py", line 297, in select
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/webhelpers2/html/tags.py", line 381, in init
File "/export/home/usname/myapp/ve/lib/python2.7/site-packages/webhelpers2/html/tags.py", line 324, in _parse_options
TypeError: lists/tuples are no longer allowed as elements in the 'options' arg: ('MM', 'Month')
I encountered this while installing formalchemy via buildout.
File "setup.py", line 7, in
ImportError: No module named six
An error occurred when trying to install FormAlchemy 1.5.3. Look above this message for any errors that were output by easy_install.
L7 of setup.py:
from six import text_type
Is this really needed?
'Value must be at least %(min)d characters long' is the error message returned. No string formatting takes place.
I'm creating a FieldSet for my User model like this:
fs = FieldSet(User)
fs.configure(pk=False,
include=[fs.picture_url.with_renderer(
FileFieldRenderer.new
(storage_path=userpic_storage_path,
url_prefix=userpic_url_prefix)
), fs.picture_url.with_renderer(
ImageFieldRenderer.new
(storage_path=userpic_storage_path,
url_prefix=userpic_url_prefix)
)])
and then rebind it to the data I get from POST request:
fs.rebind(data=request.params)
# (1)
if fs.validate():
# (2)
fs.sync()
# (3)
# save User here
else:
# report error here
Then when I render this form on web page and choose any file, it stores it in User object, but when I leave this field blank, the file removes from User object regardless of checking "Remove" checkbox. But it must not remove file if this checkbox was not checked.
When I add log.debug(fs.picture_url.value)
into positions (1), (2), (3) and leave the field blank and checkbox unchecked, I see the following in my output:
[DEBUG] ynx/frl/ljf/13389397.jpg
[DEBUG] ynx/frl/ljf/13389397.jpg
[DEBUG] None
so the correct value falls down after sync()
Is there any problems with this renderer or I just do something in the wrong way?
Thanks
Using SQLAlchemy==0.8.0b2 with FormAlchemy==1.4.2, I get the following error:
File "/.../lib/python2.7/site-packages/formalchemy/fields.py", line 21, in <module>
from sqlalchemy import exceptions as sqlalchemy_exceptions
ImportError: cannot import name exceptions
The exception module has been moved to sqlalchemy.exc, so the following
from sqlalchemy import exc as sqlalchemy_exceptions
makes it work.
What steps will reproduce the problem?
What is the expected output? What do you see instead?
TypeError: No renderer found for field mac. Type MACADDR as no default renderer
11 % endfor
12
13 % for field in fieldset.render_fields.itervalues():
14 % if field.requires_label:
15
What version of the product are you using? On what operating system?
fomalchemy: 1.4.1
sqlalchemy: 0.6.8
Please provide any additional information below.
Need to use postgres field CIDR, INET and MACADDR. How to avoid validation?
Since version 1.5.5 which released on PYPI still be affected by https://groups.google.com/forum/#!topic/formalchemy/kPqqYFc2Oxs , we need a new version of FormAlchemy to solve this issue.
It would be appreciated if we can get a newer release.
For simple fields, we can use Column.info
for attaching FA-related metdata to columns. For ManyToOne fields, we can change info
for related ForeignKey column. But for ManyToMany fields, there is not a simple way.
Suppose this schema: (simple ManyToMany relation)
class Item(Base):
__tablename__ = 'items'
id = Column(Integer, primary_key=True)
name = Column(Unicode(255))
model_items_table = Table('model_items', Base.metadata,
Column('item_id', Integer, ForeignKey(Item.id), primary_key=True),
Column('model_id', Integer, ForeignKey('models.id'), primary_key=True))
class MyModel(Base):
__tablename__ = 'models'
id = Column(Integer, primary_key=True)
name = Column(Unicode(255))
many_to_many = relationship(Item, secondary=model_items_table)
We want to change ManyToMany renderer by adding info={'renderer: ...}
keyword argument for a Column
, but which Column?
The right Column should be one of columns in intermediate table(model_items
), but adding this doesn't work for either of those two columns.
Default implementation of AttributeField.info()
only checks info
attribute of Item.id
which is not sufficient.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.