Browse files

Updated requirement of Solution>=1.1.16

  • Loading branch information...
1 parent d503d29 commit e083211b92de700ab28a8c098f84663d9c5d1ec0 @jpscaletti committed Jul 19, 2012
Showing with 58 additions and 49 deletions.
  1. +9 −3 CHANGES.md
  2. +1 −0 Makefile
  3. +1 −1 solution/__init__.py
  4. +2 −1 solution/forms/fields.py
  5. +23 −29 solution/forms/form.py
  6. +22 −15 tests/test_forms.py
View
12 CHANGES.md
@@ -1,8 +1,14 @@
# Changes
-## 1.1.15
+## 1.1.16
-- An empry data value is returned as `None` instead of `u''`.
-- When the forms of a FormSet have registered database objects with an `id` attribute, if no data is provided, those objects are automatically deleted at `form.save` time.
+- When the forms of a `FormSet` have a defined model, the objects without user data are collected at `FormSet.missing_objs` list, so the user can delete them or set a flag or something similar.
+
+- Stronger `FormSet` new forms detection: it no longer depends of a "first field" available, but any field is now enough.
+
+
+## 1.1.16
+
+- An empty data value is returned as `None` instead of `u''`.
View
1 Makefile
@@ -7,6 +7,7 @@ clean: clean-pyc
rm -rf dist
rm -rf *.egg-info
rm -rf tests/res/t
+ rm -rf tests/__pycache__
find . -name '.DS_Store' -exec rm -f {} \;
clean-pyc:
View
2 solution/__init__.py
@@ -63,7 +63,7 @@ class ToDo(db.Model):
from .custom_types import JSONEncodedType
-__version__ = '1.1.15'
+__version__ = '1.1.16'
def _create_scoped_session(db):
View
3 solution/forms/fields.py
@@ -158,7 +158,8 @@ def validate(self, cleaned_data=None):
self.error = python_value
return None
- self.has_changed = python_value != self.original_value
+ hs = (python_value or '') != (self.original_value or '')
+ self.has_changed = hs
# Do not validate optional fields
if (python_value is None) and self.optional:
return self.default or None
View
52 solution/forms/form.py
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
-import inspect
-
from pytz import utc
from .. import Model
@@ -44,7 +42,6 @@ class Form(object):
_forms = None
_sets = None
_errors = None
- _first = None
cleaned_data = None
changed_fields = None
@@ -99,9 +96,6 @@ def _init_fields(self):
is_form = isinstance(field, Form)
is_set = isinstance(field, FormSet)
- if not first and (is_field or is_form or is_set):
- first = name
-
if is_field:
field = field.make()
field.name = self._prefix + name
@@ -115,7 +109,6 @@ def _init_fields(self):
self._fields = fields
self._forms = forms
self._sets = sets
- self._first = first
def _init_data(self, data, obj, files):
"""Load the data into the form.
@@ -227,7 +220,7 @@ def save(self, parent_obj=None):
"""Save the cleaned data to the initial object or creating a new one
(if a `model_class` was provided)."""
if not self.cleaned_data:
- assert self.is_valid
+ assert self.is_valid
if self._model and not self._obj:
obj = self._save_new_object(parent_obj)
else:
@@ -261,7 +254,7 @@ def save_to(self, obj):
if not self.cleaned_data:
return
if isinstance(obj, Model):
- colnames = obj.__table__.columns.keys()
+ colnames = self._model.__table__.columns.keys()
for colname in colnames:
if colname in self.changed_fields:
setattr(obj, colname, self.cleaned_data.get(colname))
@@ -303,12 +296,10 @@ class FormSet(object):
has_changed = False
def __init__(self, form_class, parent=None,
- create_new=True, delete_old=True,
- data=None, objs=None, files=None):
+ create_new=True, data=None, objs=None, files=None):
self._form_class = form_class
self._parent = parent
self._create_new = bool(create_new)
- self._delete_old = bool(delete_old)
self._forms = []
self._errors = {}
self.has_changed = False
@@ -346,37 +337,40 @@ def _init(self, data=None, objs=None, files=None, locale='en', tz=utc):
objs = [objs]
forms = []
-
+ missing_objs = []
_prefix = 0
+
for num, obj in enumerate(objs, 1):
_prefix = num
prefix = self._get_prefix(_prefix)
- f = self._form_class(data, obj=obj, files=files, locale=locale,
- tz=tz, prefix=prefix, parent=self._parent)
+ if data and self._form_class._model and not has_data(data, prefix):
+ missing_objs.append(obj)
+ continue
+ f = self._form_class(data, obj=obj, files=files,
+ locale=locale, tz=tz, prefix=prefix, parent=self._parent)
forms.append(f)
_prefix += 1
if data and self._create_new:
forms = self._find_new_forms(forms, _prefix, data, files,
locale, tz)
+
self._forms = forms
+ self.missing_objs = missing_objs
def _get_prefix(self, num):
return '%s.%s' % (self._form_class.__name__.lower(), num)
def _find_new_forms(self, forms, _prefix, data, files, locale, tz):
"""Acknowledge new forms created client-side.
"""
- first_field_name = self._form_class()._first
prefix = self._get_prefix(_prefix)
- pname = '%s-%s' % (prefix, first_field_name)
- while data.get(pname) or files.get(pname):
+ while has_data(data, prefix) or has_data(files, prefix):
f = self._form_class(data, files=files, locale=locale, tz=tz,
prefix=prefix, parent=self._parent)
forms.append(f)
_prefix += 1
prefix = self._get_prefix(_prefix)
- pname = '%s-%s' % (prefix, first_field_name)
return forms
def is_valid(self):
@@ -396,14 +390,14 @@ def is_valid(self):
def save(self, parent_obj):
for form in self._forms:
- is_old = (form._model and form._obj and
- hasattr(form._obj, 'id') and
- hasattr(form, 'id') and form.id.empty
- )
- if self._delete_old and is_old:
- db = form._model.db
- db.query(form._model).filter(form._model.id == form._obj.id) \
- .delete(synchronize_session='fetch')
- else:
- form.save(parent_obj)
+ form.save(parent_obj)
+
+
+def has_data(d, prefix):
+ """Test if any of the `keys` of the `d` dictionary starts with `prefix`.
+ """
+ prefix = r'%s-' % (prefix, )
+ dkeys = d.keys()
+ i = filter(lambda k: k.startswith(prefix), dkeys)
+ return len(i) > 0
View
37 tests/test_forms.py
@@ -137,7 +137,7 @@ class MyContactForm(f.Form):
form = MyContactForm(data)
assert form.is_valid()
contact = form.save()
- print contact
+ print 'contact', contact.to_dict()
assert isinstance(contact, Contact)
assert contact.id is None
assert contact.subject == data['subject']
@@ -377,12 +377,18 @@ class Address(db.Model):
user = db.relationship('User',
backref=db.backref('addresses', lazy='dynamic'))
+ def __repr__(self):
+ return '<Address %s>' % (self.email,)
+
db.create_all()
class FormAddress(f.Form):
_model = Address
email = f.Email()
+ def __repr__(self):
+ return '<FormAddress %s>' % (self.email.value,)
+
class FormUser(f.Form):
_model = User
name = f.Text()
@@ -428,7 +434,7 @@ class FormUser(f.Form):
assert addr.user == user
-def test_formset_autodelete():
+def test_formset_missing_objs():
db = SQLAlchemy()
class User(db.Model):
@@ -444,13 +450,19 @@ class Address(db.Model):
user = db.relationship('User',
backref=db.backref('addresses', lazy='dynamic'))
+ def __repr__(self):
+ return self.email
+
db.create_all()
class FormAddress(f.Form):
_model = Address
id = f.Integer()
email = f.Email()
+ def __repr__(self):
+ return '<FormAddress %s>' % (self.email.value,)
+
class FormUser(f.Form):
_model = User
id = f.Integer()
@@ -459,27 +471,22 @@ class FormUser(f.Form):
user = User(name=u'John Doe')
db.add(user)
- db.add(Address(email=u'one@example.com', user=user))
- db.add(Address(email=u'two@example.com', user=user))
- db.add(Address(email=u'three@example.com', user=user))
+ a1 = Address(id=1, email=u'one@example.com', user=user)
+ db.add(a1)
+ a2 = Address(id=2, email=u'two@example.com', user=user)
+ db.add(a2)
+ a3 = Address(id=3, email=u'three@example.com', user=user)
+ db.add(a3)
db.commit()
data = {
'name': u'Jane Doe',
- 'formaddress.1-id': u'1',
'formaddress.1-email': u'one@example.org',
- 'formaddress.3-id': u'3',
'formaddress.3-email': u'three@example.org',
'formaddress.4-email': u'four@example.org',
}
+ print [(a.id, a.email) for a in user.addresses]
form = FormUser(data, user)
assert form.is_valid()
- form.save()
- db.commit()
-
- assert db.query(Address).count() == 3
- addrs = db.query(Address).all()
- assert addrs[0].email == data['formaddress.1-email']
- assert addrs[1].email == data['formaddress.3-email']
- assert addrs[2].email == data['formaddress.4-email']
+ assert form.addresses.missing_objs == [a2]

0 comments on commit e083211

Please sign in to comment.