Giter Site home page Giter Site logo

jazzband / django-formtools Goto Github PK

View Code? Open in Web Editor NEW
760.0 760.0 132.0 646 KB

A set of high-level abstractions for Django forms

Home Page: https://django-formtools.readthedocs.io

License: BSD 3-Clause "New" or "Revised" License

Python 97.28% HTML 2.09% Makefile 0.63%

django-formtools's People

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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-formtools's Issues

Pass request object to WizardView.get_prefix

This issue was originally submitted on Trac (#19981).


There was a pull request added for this issue, though it lacked tests and some documentation: django/django#879

Below is part of the description from the Trac ticket;


The pull request for this ticket simply adds the request parameter to this method. As noted in the original ticket, being able to leverage the request data for generating a unique prefix allows for a lot more flexibility. One example of this could be simply using a random token and a hidden input on each form step. There's still a TODO on the get_prefix method even indicating that some kind of unique identifier should be added, so if anyone has any ideas on what a reasonable approach for that would look like I can tackle it. – @joshdrake

NamedUrlWizardView ignores class attributes when initialising

I've noticed that when using the NamedUrlWizardView, you have to pass certain things through the as_view() method (namely url_name and done_step_name):

@classmethod
    def get_initkwargs(cls, *args, **kwargs):
        assert 'url_name' in kwargs, \
            'URL name is needed to resolve correct wizard URLs'
        extra_kwargs = {
            'done_step_name': kwargs.pop('done_step_name', 'done'),
            'url_name': kwargs.pop('url_name'),
        }

This is unlike the regular WizardView, which checks the class if it can't find the attributes in the kwargs passed to as_view (notice the getattr(cls, 'var_name', None)):

@classmethod
    def get_initkwargs(cls, form_list=None, initial_dict=None,
            instance_dict=None, condition_dict=None, *args, **kwargs):
         kwargs.update({
            'initial_dict': initial_dict or kwargs.pop('initial_dict',
                getattr(cls, 'initial_dict', None)) or {},
            'instance_dict': instance_dict or kwargs.pop('instance_dict',
                getattr(cls, 'instance_dict', None)) or {},
            'condition_dict': condition_dict or kwargs.pop('condition_dict',
                getattr(cls, 'condition_dict', None)) or {}
        })

I think that the kwargsshould be available, but they should only overwrite attributes set on the class. Looking at the class-based views docs:

Any arguments passed to as_view() will override attributes set on the class.
...
The second, more powerful way to use generic views is to inherit from an existing view and override attributes (such as the template_name) or methods (such as get_context_data) in your subclass to provide new values or methods.

modelform and formset in a wizard : bind model instance in the form

Hi,

Im using a wizard to create an Manifestation item, which have Representation.

in models.py :

class Manifestation(models.Model):
    ... fields ...

class Representation(models.Model):
    manifestation = models.ForeignKey('myapp.Manifestation')

in views.py :

class ManifestationCreateWizardView(SessionWizardView):
    #: form names
    INITIALIZATION = 'initialization'
    IMAGE = 'image'
    ORGANIZATION = 'organization'
    LIEU_DATE = 'lieu_date'
    REPRESENTATION_FORMSET = 'representation_formset'

    template_name = "base_form.html"
    file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'tmp'))
    form_list = [(INITIALIZATION, ad_forms.ManifestationWizardForm0),
                     (IMAGE, ad_forms.ManifestationWizardForm1),
                     (ORGANIZATION, ad_forms.ManifestationWizardForm2),
                     (LIEU_DATE, ad_forms.ManifestationWizardForm3),
                     (REPRESENTATION_FORMSET, ad_forms.ManifestationWizardForm4)]

    condition_dict = {LIEU_DATE: selected_domain_requires_representations,
                      REPRESENTATION_FORMSET: selected_domain_does_not_require_representations}

    def dispatch(self, request, *args, **kwargs):
        dispatch = super(ManifestationWizardCreateView, self).dispatch(request, *args, **kwargs)
        instance = self.get_form_instance(self.steps.current)
        self.instance_dict = {self.INITIALIZATION: instance,
                                  self.IMAGE: instance,
                                  self.ORGANIZATION: instance,
                                  self.LIEU_DATE: instance,
                                  self.REPRESENTATION_FORMSET: instance}
        # I'm sure to use the same instance of `Manifestation` inside my wizard
        return dispatch

    def get_form_instance(self, step):
        """
        Gets the initialized instance of the `Manifestation` item
        :param step: requested step
        :return: model instance
        """
        pk = self.kwargs.get('pk')
        if pk:
            if not self.instance:
                self.instance = models.Manifestation.objects.get(pk=pk)
        else:
            if self.instance is None:
               self.instance = models.Manifestation()
        return self.instance

in forms.py :

class ManifestationWizardForm4(ManifestationWizardForm):
    """
        `representation_formset` form
    """
    class Meta:
        model = models.Manifestation
        fieldsets = [('infos', {'legend': u"Récapitulatif", 'fields': ('titre', )}),]
        widgets = {'titre': u_widgets.ReadOnlyTextInput,}

    #: formset to representations, build with an inlineformset_factory
    formset = RepresentationManifestationFormSet()

    # I override the form initializazion to set instance to formset.instance 
    def __init__(self, *args, **kwargs):
        super(ManifestationWizardForm4, self).__init__(*args, **kwargs)
        if self.instance:
            self.formset.instance = self.instance

    def is_valid(self):
        form_is_valid = super(ManifestationWizardForm4, self).is_valid()
        formset_is_valid = self.formset.is_valid()
        settings.DEBUG and logger.debug(u'ManifestationWizardForm4::is_valid() '
                                            u'form_is_valid = %s / formset_is_valid = %s',
                                            form_is_valid, formset_is_valid)
        # formset seems to not be bound, even if I fill it 
        if settings.DEBUG and not formset_is_valid:
            logger.debug(u'ManifestationWizardForm4::is_valid() '
                                  u'formset.errors = %s / forms.forms.errors = %s',
                                  self.formset.errors, [f.errors for f in self.formset.forms])
        return form_is_valid and formset_is_valid

When I save the form, the formset does not seems to be bound to data, so it not valid, so I can't save it. I've tryed to

Thanks about your work !

Add validation step for interdependent forms in WizardView render_done method

WizardView is currently missing a validation step for interdependent form data. Forms are only validated individually.

I see two ways to make this happen in a backwards compatible manner:

  1. Add an additional method which is passed all validated forms. It has the opportunity to set something analogous to a form's NON_FIELD_ERRORS and redirect the user to a specific step. It should be called in the render_done() method after forms are revalidated but before done() is called. I.e. https://github.com/django/django-formtools/blob/master/formtools/wizard/views.py#L351

  2. Similar to 1, but let this happen in the done() method. The done() method would need to be able to prevent the Wizard from calling self.storage.reset().

Since the done() method is already passed all of the revalidated forms, I think providing the it with a way to prevent the Wizard from calling self.storage.reset() would allow the done() method to handle interdependent form data validation and also potentially provide the tools necessary to have users confirm submitted data which would also fix issue #17

FormPreview should pass request object to parse_params

This issue was originally submitted on Trac (#8690). See the previous link for the full conversation. Below is the original description:


It would be very useful to have request data in parse_params. The example given is to capture something like a user_id, but the main thing I would want to do here is to verify that the current user has permission to access the URL given. Of course, adding a parameter breaks backwards compatibility, so this is a similar request to http://code.djangoproject.com/ticket/7222.

wizard NamedUrlWizardView post method is redundant?

The wizard NamedUrlWizardView inherits from WizardView.

This is all the code in NamedUrlWizardView post method override:

        wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
        if wizard_goto_step and wizard_goto_step in self.get_form_list():
            return self.render_goto_step(wizard_goto_step)
        return super(NamedUrlWizardView, self).post(*args, **kwargs)

This is the code at the start of WizardView post method:

        wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
        if wizard_goto_step and wizard_goto_step in self.get_form_list():
            return self.render_goto_step(wizard_goto_step)

Is there any reason for the NamedUrlWizardView post method, if the WizardView post does the same thing straight away?

A reason to remove the duplication would be to reduce the number of calls to get_form_list, which in turn evaluates all the form condition callables.

Class based view update for FormPreview

This issue was originally submitted on Trac (#16174). Please see that ticket for the original conversation.

NOTE: There are a few patches attached to the Trac ticket which may be useful.


I used the FormPreview class in formtools.preview for the first time this week. After working with class based views for a while, I really missed methods like get_form for custom form instantiation. Recently, the form wizard machinery (which is much more complex) got a class-based views update (#9200) so I decided to update the FormPreview class as well. It uses django.views.generic.FormView and it's on a Django branch on my Github account. (​https://github.com/ryankask/django/blob/cbv-formpreview/django/contrib/formtools/preview.py -- I've also attached a diff based on the Django Github mirror which I am pretty sure is acceptable.

In order to maintain 100% compatibility, there are some issues to note:

  • The original class used get_context whereas the class based views use get_context_data. I've made it so both can be used but if backwards compatibility can be broken, it would be better to only use get_context_data.
  • The original class used __call__ so it could be easily instantiated with a form in a urlconf. I moved the important code to dispatch and __call__ just returns a call to dispatch.
  • The failed_hash method, which isn't documented, falls under a section in the code which says "METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE." I left the ability to call that method and it just wraps post and sets the current stage to preview.
  • get_initial, process_preview, and security_hash, which all fall under the "override if you need to" section only documented in the code, used to take a request as an argument. They all still do. The methods that were marked "don't touch" now use the instance's request.

If backwards compatibility doesn't need to be maintained, the code can be cleaned up a little more.

Anyway, any comments on the patch would be much appreciated and I'd update the docs if devs think it's okay.

By the way, if none of this is acceptable, the test formtools.PreviewTests.test_form_submit_bad_hash needs to be fixed (it is in my patch). self.client.post('/previewpreview/', self.test_data) results in a 404 so the next assertion that some text isn't in the template passes when it shouldn't.

Forms with CookieWizardView fail silently if forms are too large

I was having a strange bug where I could go all the way through my wizard with no validation errors, but then when hitting the final submit I'd be taken back to an earlier step (now blank) with no validation errors. And looking inside render_revalidation_failure I could see that the form was now unbound.

I eventually figured out that the problem was that cookies have a maximum length (around 4096 bytes) and Django will silently fail to set a cookie if it's too large. One of my forms had several dozen fields (not ideal UX I know) and so CookieStorage.update_response is called, it silently fails to update the cookie. And then when WizardView.render_done tries to revalidate all the data at the end of the wizard, it fails to find any data for the offending large step and thus fails to validate.

This is clearly an edge case and it seems that the main Django project examined the issue of large cookies and decided to do nothing. But this is a very confusing failure when it happens. Adding some kind of validation that the cookie has actually been successfully modified and throwing a clear exception if it hasn't would make this rare problem way easier to debug or avoid.

Error handling in done()

Is there a way to handle errors in done() so that the form data in the storage is not cleared?

If the processing fails, I want to offer the user a possibility to re-process the data without having to re-fill the entire form.

Question?

I asked this at https://groups.google.com/forum/#!searchin/django-users/formtools/django-users/YA4x3qQPGQA/WNkLWVPQCAAJ but never received an answer. I don't know if this is the right place to ask this, but here goes.

I'm wondering if I can use django-formtools to accomplish what I want to. I have a License object, with a one to many relationship to LicenseArea. The number of LicenseArea objects varies for each license, so I would like a wizard that has:

Step 0 - the license data
Step 1 - the common data for all LicenseArea objects
Step 2-through n - The same form for each LicenseArea to enter the unique data for each LicenseArea

I've currently implemented this as two steps, one for the License, and then a Formset for each LicenseArea, but as the amount of data for each LicenseArea is significant, the UI leaves a great deal to be desired. I was thinking one step for each LicenseArea would work better. Is this possible, and if so, how best would I implement this? Thanks.

PyPI release for django 1.10 compatibility

Hello,

I would like about new PyPI releases of django-formtools. Django 1.10 was released. 46b6839 contains fix for django 1.10 compatibility (below are stacktrace without that). 54f1ccc proves that django-formtools is django 1.10 compatibile. I think is good to release django-1.10-compatible version of django-formtools.

$ python manage.py test feder --keepdb
Using existing test database for alias 'default'...
...................E........................................................................................
======================================================================
ERROR: test_permitted_user (feder.letters.tests.test_view.ReplyPermissionTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/adas/Devel/feder/feder/letters/tests/test_view.py", line 85, in test_permitted_user
    response = self.client.get(self._get_url())
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/test/client.py", line 529, in get
    **extra)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/test/client.py", line 333, in get
    return self.generic('GET', path, secure=secure, **r)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/test/client.py", line 409, in generic
    return self.request(**r)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/test/client.py", line 494, in request
    six.reraise(*exc_info)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
    response = self._get_response(request)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/utils/decorators.py", line 185, in inner
    return func(*args, **kwargs)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/home/adas/Devel/feder/feder/letters/views.py", line 94, in __call__
    return method(request)
  File "/home/adas/.virtualenvs/feder/local/lib/python2.7/site-packages/formtools/preview.py", line 58, in preview_get
    context_instance=RequestContext(request))
TypeError: render_to_response() got an unexpected keyword argument 'context_instance'

----------------------------------------------------------------------

Form Preview does not work with file uploads

This issue was originally submitted on Trac (#7808). See the previous link for the full conversation. Below is the original description:


There seems to be no way to bind a form to a Form Preview (using request.FILES)...
i tried ignoring the specific warning not to override in preview.py and tried to override the preview_post() method but this did not work.

Additionally this is not documented on ​http://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-preview/

Add more details about Django version suport

Docs currently say "the app is required to be working with the actively maintained Django versions." Does this mean formtools must support multiple versions of Django? Maybe the plan isn't known at this time, but more details should be added at some point. I see Travis is currently running with master and 1.7

FormWizard validates the last form twice

This issue was originally submitted on Trac (#10810). See the previous link for the full conversation. Below is the original description:


FormWizard revalidates all the forms on the last step, after validating the last form. So the last one gets validated twice on the same request. In my app I have captcha on the last form and it does not work with revalidation (and should not I think).
I've made changes to wizard.py, patch attached (see original Trac issue).

Allow dynamic form classes with WizardView

This issue was originally submitted on Trac (#21667). I've added some snippets from the original ticket below, see the link above for the full conversation.


The WizardView does not currently support dynamic form classes without overriding the entire get_form method.

My mixin below demonstrates an easy way to make this convenient. I needed this functionality to support using modelform_factory at runtime to accommodate logic that varies depending on choices made previously in the wizard. A simple use case is to support dynamic "required" fields.

class WizardDynamicFormClassMixin(object):
    def get_form_class(self, step):
        return self.form_list[step]

    def get_form(self, step=None, data=None, files=None):
        """
        This method was copied from the base Django 1.6 wizard class in order to
        support a callable `get_form_class` method which allows dynamic modelforms.

        Constructs the form for a given `step`. If no `step` is defined, the
        current step will be determined automatically.

        The form will be initialized using the `data` argument to prefill the
        new form. If needed, instance or queryset (for `ModelForm` or
        `ModelFormSet`) will be added too.
        """
        if step is None:
            step = self.steps.current
        # prepare the kwargs for the form instance.
        kwargs = self.get_form_kwargs(step)
        kwargs.update({
            'data': data,
            'files': files,
            'prefix': self.get_form_prefix(step, self.form_list[step]),
            'initial': self.get_form_initial(step),
        })
        if issubclass(self.form_list[step], forms.ModelForm):
            # If the form is based on ModelForm, add instance if available
            # and not previously set.
            kwargs.setdefault('instance', self.get_form_instance(step))
        elif issubclass(self.form_list[step], forms.models.BaseModelFormSet):
            # If the form is based on ModelFormSet, add queryset if available
            # and not previous set.
            kwargs.setdefault('queryset', self.get_form_instance(step))
        return self.get_form_class(step)(**kwargs)

This is a simple demonstration of usage:

def get_form_class(self, step):
    if step == STEP_FOO:
        try:
            choice_foo = self.get_cleaned_data_for_step(STEP_FOO)["choice_foo"]
        except KeyError:
            pass
        else:
            # get_wizard_form_class() would return a model form with fields
            # that depend on the value of "choice"
            return ModelFoo(choice=choice_foo).get_wizard_form_class()
    return super(WizardFoo, self).get_form_class(step)

remove the Django>=1.7 dependency in setup.py

Obviously only if the package actually works with Django 1.6.

The reason being that we maintain a package that still supports Django 1.6 (django-cms 3.2.x). So for 1.7+ we add a dependency to django-formtools. Unfortunately it is not possible to conditionally install a dependency, only if a certain version of a other package is present. So even if our package is used in a Django 1.6.x Project we still have to install django-formtools. This is especially a problem with strict dependency checkers like pip-tools.

Thus we'd like to use django-formtools for Django 1.6.x, even if we could also use the builtin version.

Multiple calls to clean method

Hi,

i used forms tools to import data,
first step it's a form that expect a file and some informations
the second is a form that display what is going to be imported with checkboxes to confirm which one we want.
then the user confirms the import.
Everything works but while debugging if i set a breakpoint in the clean method of the last form i noticed that that it's called 5 times at least...
Anyone know why ?
The actual import is done on the last clean method for dynamic reasons.
I found a reference to this odd behaviour with no answer :
http://stackoverflow.com/questions/18983032/django-wizard-form-instantiated-and-clean-called-multiple-times

it's very problematic because the heavy computation is taking place in this function so i can't alllow this.

Formtools chokes when ‘current_step’ has unexpected value

Hello,

I tested in 1.6 but it looks like this behaviour is still the same:
https://github.com/django/django-formtools/blob/master/formtools/wizard/views.py#L408

A user has been tampering with the current_step part of a POST request that is part of a the Django Form Wizard. The current step should be something like ‘request-sim’ but the user changes it to ‘-’. Formtools does not seems to check whether the step actually exists. So it raises a KeyError when trying to access it.

Could this error be handled more gracefully? Catch the KeyError and respond with a Bad request if the step has been tampered with?

Thanks a bunch for Django+formtools,
Cheers!

This is the exception:

KeyError: u"'"

Stacktrace (most recent call last):

File "django/core/handlers/base.py", line 112, in get_response
  response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "django/views/generic/base.py", line 69, in view
  return self.dispatch(request, *args, **kwargs)
File "mvne/new_registration_wizard/views.py", line 106, in dispatch
  response = super(RegistrationWizardView, self).dispatch(request, *args, **kwargs)
File "django/contrib/formtools/wizard/views.py", line 236, in dispatch
  response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "django/views/generic/base.py", line 87, in dispatch
  return handler(request, *args, **kwargs)
File "django/contrib/formtools/wizard/views.py", line 673, in post
  return super(NamedUrlWizardView, self).post(*args, **kwargs)
File "django/contrib/formtools/wizard/views.py", line 286, in post
  form = self.get_form(data=self.request.POST, files=self.request.FILES)
File "django/contrib/formtools/wizard/views.py", line 406, in get_form
  'prefix': self.get_form_prefix(step, self.form_list[step]),

This is the data from the post request:

u' order by 1000000000--'   u''
u'csrfmiddlewaretoken'  u'x77Ea73S7gcJlc3q1TbwjFnK4pics6PU'
u'echo phpinfo()'   u''
u'registration_wizard_view-current_step'    u'''
u'request-sim-mgm_form-friend'  u'0'
u'request-sim-sim_type_form-sim_type'   u’'

FormWizards leak data into other forms

This issue was originally submitted on Trac (#22899). I've added some snippets from the original ticket below, see the link above for the full conversation.

Consider an events booking system where someone selects their tickets, adds their payment information but then decides to navigate away on the last page. If they then went to a different event all of their payment information etc would be shown as the initial data in the new form, even though it's on a completely different URL with completely different content. This really shouldn't be happening. It would be useful to limit the form data to a specific form, either by URL or by some sort of form hash which is different for each form. – @danielsamuels

...

Say for example you have a form where you enter your address information for a specific item, so your URL is /item/4/form/, you then go to /item/5/form/ which technically is the same FormWizard - but for a different item - the information you entered in the first form, if you didn't complete it, will be displayed on the 2nd form even though you've never been to that page before. So it's the same FormWizard used in different contexts, but the data from one appears in the other. – @danielsamuels

...

Jupp, this is the result of ​https://github.com/django/django/blob/master/django/contrib/formtools/wizard/views.py#L195-L197 -- a quick workaround would be to create a subclass in the view which includes the ID :( If you'd like to work on a real fix I think we should add a random hash to it and send it along via the management form. – @apollo13

FormWizard needs confirmation step logic

This issue was originally submitted on Trac (#21644). I've added some snippets from the original ticket below, see the link above for the full conversation.


The FormWizard needs to handle a confirmation step that is capable of easily outputting a readonly copy of all step data. It is currently very difficult to support a confirmation step in the FormWizard workflow. The confirmation step needs access to the "final_form_list" created in the render_done() method and passed to the done() method. This is important so the user can see the data he is confirming.

I.e. the confirmation step as presented in the documentation ​https://docs.djangoproject.com/en/1.6/ref/contrib/formtools/form-wizard/#using-a-different-template-for-each-form does not satisfy the requirements for confirmation since the user cannot actually see his order that he is supposed to confirm.

This could be worked into the render_done() method, or broken into two steps. However, currently, one must duplicate a ton of code to render a confirmation view that outputs a readonly copy of the previous steps.

This could be implemented in a way that allows the developer to "opt out" of the confirmation if the specific FormWizard in question does not need a confirmation step.

EDIT: this cannot currently be performed easily in the done() method override because render_done() calls self.storage.reset() after it calls the done() method.

Doesn't work with formsets

Hello,
I use a simple formset:

class EventItemsForm(forms.Form):
    quantity = forms.IntegerField()
    options = forms.ModelChoiceField(queryset=ProductOption.objects.all(), required=False)

EventItemsFormset = formset_factory(EventItemsForm)

With the NamesUrlSessionWizardView.

When I get to the step using a formset, I get an exception:

KeyError at /events/1563/register/items/

0

It looks like this is really ancient error that was "fixed" at least two times. But it still doesn't work. :(

Admin support

This is a feature request basically just to start a conversation on the matter.

Especially with the new admin look, the admin is ideal for simple (or not) data entry. I think that having django-formtools available in the admin would provide some much needed logic and customization potential for developers.

Even though the last time I meddled with the admin I found it a troubling procedure, I think it is worth giving it a try when I have some time.

Also, please do share directions or similar efforts having been done already by others

Enhancement for MultiFileField

Update set_step_files() to handle MultiFileField (https://github.com/Cyberic/django-multifilefield):
<MultiValueDict: {'attachment': [<InMemoryUploadedFile: file1.txt (text/plain)>, <InMemoryUploadedFile: file2.txt (text/plain)>]}>

def set_step_files(self, step, files):
        if files and not self.file_storage:
            raise NoFileStorageConfigured(
                "You need to define 'file_storage' in your "
                "wizard view in order to handle file uploads.")

        if step not in self.data[self.step_files_key]:
            self.data[self.step_files_key][step] = {}

        for key in files.keys(): ---> CHANGED!!
            for field_file in files.getlist(key):  ---> CHANGED!!
                tmp_filename = self.file_storage.save(field_file.name, field_file)
                file_dict = {
                    'tmp_name': tmp_filename,
                    'name': field_file.name,
                    'content_type': field_file.content_type,
                    'size': field_file.size,
                    'charset': field_file.charset
                }
                self.data[self.step_files_key][step][key] = file_dict  ---> CHANGED!!

WizardView.done() uses render_to_response() which might get deprecated in the future

WizardView.done() uses the function render_to_response(), instead of the newer render() function:

https://docs.djangoproject.com/en/1.9/topics/http/shortcuts/#render
https://docs.djangoproject.com/en/1.9/topics/http/shortcuts/#render-to-response

This function [render_to_response()] preceded the introduction of render() and works similarly except that it doesn’t make the request available in the response. It’s not recommended and is likely to be deprecated in the future.

Not presently a show stopper but might be in the future.

Support FormWizard without the base view

A common paradigm we're using while refactoring Sentry is inheriting from various base View classes. This is specifically to enforce authorization and acls. FormWizard provides a lot of nice behaviors, but it requires you to inherit from Django's CBVs. It'd be nice if FormWizard was a helper that wasn't bound to View behavior. Generally all of the generic Django CBVs have this issue, but FormWizard is a bit more trivial to adapt to than TemplateView.

Having multiple formsets on a page leads to all of them using the same Management Form

I need two Formsets on the same page

FORM = [("2", (
             ("a", FormsetA),
             ("b", FormsetB),
         ))]

I had to explicitly do the following to avoid ManagmentForm errors

{{ wizard.forms.0.management_form }}
{{ wizard.forms.1.management_form }}

But they both generate the exact same sort of Management Form hidden field. Whenever I manipulated the TOTAL-FIELDS with Javascript, both forms get updated, which is clearly not what I wanted. After digging through the code I extended the get_form_prefix method to look like this

    def get_form_prefix(self, step=None, form=None):
        if step is None:
            step = self.steps.current
        if isinstance(form, str):
            step = step + "-" + form
        return str(step)

And that gave me the right results, which I think should be how it works

ValidationError in form wizard with formsets

This issue was originally submitted on Trac (#20116). See the previous link for the full conversation, and a link to an initial fix.


I encountered an issue with the form wizard when the first step is a formset and the user resends a later step after completing the wizard.

Scenario:

  • Complete the wizard successfully
  • Hit the browser back button (page usually comes from cache then)
  • Send the last form again

Because the wizard's storage gets reseted after completion, the wizard will start with the first step. If the first step is a formset, its ManagementForm raises a ValidationError because the data is passed but doesn't contain the expected values.

Some of the files submitted using formsets are missing

Occured when using formset which contains few instances of the same form class (with file fields) in a single step.
It's caused by MultiValueDict.__getitem__ method which returns only last element of values list:
https://github.com/django/django/blob/master/django/utils/datastructures.py#L84

For example:
In one single step we have 3 instances of form which contains file field - and only the file from last step is saved when using form_dict['our_step'].save() method. That means the files submitted in the first 2 forms are lost forever, which is IMO not desired behaviour by default.

As a workaround we can override get_form_step_files() method and extract all files one by one using MultiValueDict's getlist method:

    def get_form_step_files(self, form):
        ret = {}
        for key in form.files.keys():
            for i, file_ in enumerate(form.files.getlist(key)):
                ret["{}-{}".format(key, i)] = file_

        return ret

And then save it properly in done() method:

        formset = form_dict['our_step']
        for i, form in enumerate(formset):
            form.instance.avatar = formset.files[
                "{}-{}-{}".format('our_step', 'avatar', i)]

            form.instance.family = formset.files[
                "{}-{}-{}".format('our_step', 'family', i)]

            form.save()

Missing base.html

Hello,

Maybe I am missing something, but the FormPreview templates are trying to extend "base.html" which is nowhere to be found in the repo. I've tried to run the basic FormPreview example from the docs, and it doesn't work because of this.

Am I supposed to provide a base.html somehow?

Thanks,
Bill

Set up google group

Not sure if there is enough action to warrant it, but I find it easier to follow discussions and coordination on a discussion board like google groups. Any objections or opinions?

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.