Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
language: python
python: 2.7
env:
- TOX_ENV=py26-14
- TOX_ENV=py26-16
- TOX_ENV=py27-14
- TOX_ENV=py27-16
- TOX_ENV=py27-17
- TOX_ENV=py27-18
- TOX_ENV=py27-19
- TOX_ENV=py33-16
- TOX_ENV=py33-17
- TOX_ENV=py34-16
- TOX_ENV=py34-17
- TOX_ENV=py27-110
- TOX_ENV=py34-18
- TOX_ENV=py34-19
- TOX_ENV=py34-110
- TOX_ENV=py35-18
- TOX_ENV=py35-19
- TOX_ENV=pypy-14
- TOX_ENV=pypy-16
- TOX_ENV=pypy-17
- TOX_ENV=py35-110
- TOX_ENV=pypy-18
- TOX_ENV=pypy-19
- TOX_ENV=pypy-110
- TOX_ENV=docs
- TOX_ENV=flake8
install:
Expand Down
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ Changelog
-----
* Fix formset rendering in Django 1.9. `#17`_
* Add support for Django 1.9's ``get_bound_field``. `#18`_
* Remove need for a custom metaclass. Formsets and forms now
show up in ``form.cleaned_data`` after validation in addition to the
``SuperForm.forms`` and ``SuperForm.formsets`` attributes. `#19`_

.. _#17: https://github.com/gregmuellegger/django-superform/pull/17
.. _#18: https://github.com/gregmuellegger/django-superform/pull/18
.. _#19: https://github.com/gregmuellegger/django-superform/pull/19

0.3.1
-----
Expand Down
3 changes: 2 additions & 1 deletion django_superform/boundfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def __iter__(self):
for item in self.form.get_composite_field_value(self.name):
yield item

# __len__, no changes required
def __len__(self):
return len(list(self.__iter__()))

def __getitem__(self, item):
"""
Expand Down
77 changes: 15 additions & 62 deletions django_superform/fields.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,11 @@
from django.forms.models import inlineformset_factory
from django.forms import Field

from .boundfield import CompositeBoundField
from .widgets import FormWidget, FormSetWidget


class BaseCompositeField(object):
"""
The ``BaseCompositeField`` takes care of keeping some kind of compatibility
with the ``django.forms.Field`` class.
"""

widget = None
show_hidden_initial = False

# Tracks each time a FormSetField instance is created. Used to retain
# order.
creation_counter = 0

def __init__(self, required=True, widget=None, label=None, help_text='',
localize=False, disabled=False):
self.required = required
self.label = label
self.help_text = help_text
self.disabled = disabled

widget = widget or self.widget
if isinstance(widget, type):
widget = widget()

# Trigger the localization machinery if needed.
self.localize = localize
if self.localize:
widget.is_localized = True

# Let the widget know whether it should display as required.
widget.is_required = self.required

# We do not call self.widget_attrs() here as the original field is
# doing it.

self.widget = widget

# Increase the creation counter, and save our local copy.
self.creation_counter = BaseCompositeField.creation_counter
BaseCompositeField.creation_counter += 1


class CompositeField(BaseCompositeField):
class CompositeField(Field):
"""
Implements the base structure that is relevant for all composite fields.
This field cannot be used directly, use a subclass of it.
Expand Down Expand Up @@ -152,33 +111,28 @@ class RegistrationForm(SuperForm):
widget = FormWidget

def __init__(self, form_class, kwargs=None, **field_kwargs):
self.form_class = form_class
super(FormField, self).__init__(**field_kwargs)

self.form_class = form_class
if kwargs is None:
kwargs = {}
self.default_kwargs = kwargs

def get_form_class(self, form, name):
"""
Return the form class that will be used for instantiation in
``get_form``. You can override this method in subclasses to change
the behaviour of the given form class.
"""
return self.form_class

def get_form(self, form, name):
"""
Get an instance of the form.
"""
kwargs = self.get_kwargs(form, name)
form_class = self.get_form_class(form, name)
form_class = self.form_class
composite_form = form_class(
data=form.data if form.is_bound else None,
files=form.files if form.is_bound else None,
**kwargs)
return composite_form

def widget_attrs(self, widget):
return {'form_class': self.form_class}


class ModelFormField(FormField):
"""
Expand Down Expand Up @@ -295,7 +249,7 @@ def get_kwargs(self, form, name):
kwargs['empty_permitted'] = True
return kwargs

def get_field_name(self, form, name):
def get_field_name(self, name):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the form parameter removed here? It's not used in the implementation, but during writing this it made sense to me since this way most methods have the same signature which is easy to remember and contains all information relevant for the field that cannot be accessed via self.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was some refactoring I did trying to understand the code. I found it difficult to figure out what a lot of parameters were for, which made it harder to understand what information I actually needed for which methods. In particular, get_form_class had a superfluous form parameter, which was inconsistent with the changes I wanted to make, since widget_attrs needed access to the form_class, but didn't have direct access to the form. I may be able to fix that using the "monkeypatching" you mentioned.

It sounds like we have differing ways of thinking about interfaces, but it's your project. 😃 I'll update the code to only remove the superfluous form parameter in cases where it's necessary to remove it.

return self.field_name or name

def allow_blank(self, form, name):
Expand All @@ -306,15 +260,11 @@ def allow_blank(self, form, name):
if self.blank is not None:
return self.blank
model = form._meta.model
field = model._meta.get_field(self.get_field_name(form, name))
field = model._meta.get_field(self.get_field_name(name))
return field.blank

def get_form_class(self, form, name):
form_class = self.form_class
return form_class

def get_instance(self, form, name):
field_name = self.get_field_name(form, name)
field_name = self.get_field_name(name)
return getattr(form.instance, field_name)

def save(self, form, name, composite_form, commit):
Expand All @@ -326,7 +276,7 @@ def save(self, form, name, composite_form, commit):
saved_obj = super(ForeignKeyFormField, self).save(form, name,
composite_form,
commit)
setattr(form.instance, self.get_field_name(form, name), saved_obj)
setattr(form.instance, self.get_field_name(name), saved_obj)
if commit:
form.instance.save()
else:
Expand All @@ -349,9 +299,9 @@ class FormSetField(CompositeField):
widget = FormSetWidget

def __init__(self, formset_class, kwargs=None, **field_kwargs):
self.formset_class = formset_class
super(FormSetField, self).__init__(**field_kwargs)

self.formset_class = formset_class
if kwargs is None:
kwargs = {}
self.default_kwargs = kwargs
Expand All @@ -376,6 +326,9 @@ def get_formset(self, form, name):
**kwargs)
return formset

def widget_attrs(self, widget):
return {'formset_class': self.formset_class}


class ModelFormSetField(FormSetField):
def shall_save(self, form, name, formset):
Expand Down
Loading