Hi, thanks for taking time to provide such a detailed answer.
> You can and should split up your code into separate functions however > you like. Form validation can be done in a separate function that > returns a dictionary that is used to update the context of the calling > view, for example. Your alternate solution sounds a bit complex for > working around the things you've described, but c'est la vie... While it may sound complex, it allows me to write the actual views and handlers really simply. For example, I have this one-statement view dispatcher: @access_restricted def brochure_page(request, brochure_id, page): return item_or_404({ "property_address" : show_form_property, "property_building" : show_form_property, "documents" : show_form_brochure, "pdf" : show_form_pdf, ... }, page)( request, enforce_editable(get_object_or_404(models.brochure, pk=brochure_id), request.user), page, ) and this one-statement function powers several pages at once: def show_form_property(request, brochure, page): return response_from_main(brochure, page, request, form=forms.by_page(page)(data=attempted_post(request), instance=brochure.property)) this one, on the contrary, shows two forms on one page: def show_form_pdf(request, brochure, page): return response_from_main(brochure, page, request, form_brochure_xslfo=forms.brochure_xslfo(data=attempted_post(request), instance=brochure), form_pdf_map_new=forms.brochure_pdf_map(data=attempted_post(request)), ) and this one-statement handler processes submissions generated by the former: @post_handler(action="update_property", next=redirect_to_console_page()) @access_restricted @autoload_require_editable(models.property, pk="property_id") def do_update_property(request, property): enforce_valid(forms.by_page(request.POST["page"])(request.POST, instance=property)).save() While this handler uses request.POST["page"] to know where to redirect, the following one creates an object and returns a URL to it explicitly: @post_handler(action="create_photo") @access_restricted @autoload_require_editable(models.feature, pk="feature_id") def do_create_photo(request, feature, property): enforce_valid(forms.photo(request.POST, request.FILES, instance=models.photo(feature=feature))).save() return url_from_view(feature_edit, brochure_id= request.POST["brochure_id"], feature_id=feature.pk) So my views contain not a single statement that would be related to form _processing_, and handlers are likewise agnostic of views. > I don't really understand all the stuff about ignoring the URL in your > solution The idea is that every form does its POST to its own URL, so the POST contains two pointers: one, contained in the “submission” parameter, tells the application what to do with the data submitted, and the URL tells it what to do in case validation fails. If it succeeds, the target of the redirect is deduced from POST. So, for example, a form looks like this in HTML: <form action="" method="post"> <input type="hidden" name="submission" value="add_tag" /> <input type="hidden" name="brochure_id" value="4" /> <input type="hidden" name="property_id" value="6" /> <input type="hidden" name="page" value="brochure_tags" /> <input type="text" name="tag" /> <input type="submit" /> </form> If everything’s OK, the app never looks at the request URI. Only if there’s a validation failure, the middleware lets Django find the view that corresponds to the URI--which is the same view that caused the POST--and the view will display the form(s) again, noting the errors. I used to have all POSTs directed to a single URI and pass the needed parameters in the request body. However, that did not allow for user-friendly form validation, so I made all //form/@action empty, but the parameters stayed where they had been before. There’s no need for user-friendly URLs when doing POST, they aren’t even shown to the user anyway (as long as submissions succeed), they are only relevant in the case the POST handler can’t do a redirect. While that’s not too semantic, it preserves shareable/bookmarkable URLs in all cases. Every URL is guaranteed to return the same form. For a simple example, let there be two pages that have similar forms that allow editing something. /admin/posts/2009/01/04/hello-world <form action="???" method="post"> <input type="hidden" name="post_id" value="42" /> Title: <input type="text" name="title" value="Hello world!" /> Text: <textarea>...</textarea> </form> /admin/posts/2009/01/ <form action="???" method="post"> <input type="hidden" name="post_id" value="41" /> Title: <input type="text" name="title" value="First post!" /> Text: <textarea>...</textarea> </form> <hr /> <form action="???" method="post"> <input type="hidden" name="post_id" value="42" /> Title: <input type="text" name="title" value="Hello world!" /> Text: <textarea>...</textarea> </form> What should be in the action field? If there’s the same URL, maybe /admin/posts/edit, then a failed form validation would show that URL in the address field, hardly helpful. What if a user wants to ask someone for help, how can he/she indicate which page is causing problems? But if each form has action="", then the URL will be meaningful. > Since #6094 is about handling exceptions in middleware, and you want > exception handling in middleware to work as described in #6094, the > answer to your question is "yes". OK. Until then, I’ve added this to my middleware, copied from Django source: except: if django.db.transaction.is_dirty(): django.db.transaction.rollback() django.db.transaction.leave_transaction_management() if not settings.DEBUG or settings.DEBUG_PROPAGATE_EXCEPTIONS: raise return django.views.debug.technical_500_response(request, *sys.exc_info()) Hopefully it’s not too dirty a hack? -- TIA Roman.
smime.p7s
Description: S/MIME cryptographic signature