Visitar URL original
Processing POST request in several Content Types · Issue #604 · feincms/feincms · GitHub
Skip to content

Processing POST request in several Content Types #604

Description

@paramono

I am trying to put two different forms on a single page. These forms are implemented in the same manner as the bundled ContactFormContent. Basically, they have a form class and a model class, where the model class has process() method that handles requests.

If I add one of these forms to the page, everything works fine: when user submits the form, process() handles the POST request, and performs all the necessary logic. However, if both of these forms are present on the same page, the second form will be processed in the process() method of the first one.

This seems to be logically correct: since templates of the both forms contain method="post" action=".", the submitted form is processed by the first handler found on the same page. However, if I comment out the entire process() method of the first form, the second form processes GET requests only, and completely ignores POST requests for some reasons. As the result, django returns status code 405 when I submit the second form, just as if POST handler was not defined at all.

I found the code that runs process() in each content type at module/mixins.py. I tried analyzing request data to check which form was submitted, and, if it was the wrong form, returning True in process(), to give another form a chance to run its process() afterwards, but that didn't help.

What may be the issue here? Is it possible to put different forms, defined as two different content types, on the same page in feincms? What is the correct way to handle POST requests in different content types present on the same page?

Activity

  1. mjl commented on Nov 28, 2015

    @mjl
    Contributor

    The problem is that you are returning something from process(). This will short-circuit the evaluation of further content types and use the HttpResponseRedirect returned as the overall return value of the page. FeinCMS assumes that if a content type returns a HttpResponseSomething, it has a deeper reason for doing that and the rest of the page won't be rendered anyway, so it won't process any further content types.

    That means the easiest way to make both content types work is not to return something from process().

    Perhaps we should process() all CTs anyway? Opinions?

  2. paramono commented on Nov 29, 2015

    @paramono
    ContributorAuthor

    The problem is that you are returning something from process(). This will short-circuit the evaluation of further content types and use the HttpResponseRedirect returned as the overall return value of the page. FeinCMS assumes that if a content type returns a HttpResponseSomething

    Not exactly. Yes, you can short-circuit evaluation if you return HttpResponseSomething from your CT, but you can return True, letting other content types to be processed normally. I noticed that this is what occurs in case of GET, and so investigated a bit further why I am getting problems with POST. Look for the link to mixins module below.

    Perhaps we should process() all CTs anyway? Opinions?

    It seems that all content types are actually processed:
    feincms.module.mixins

    I realized that the origin of my issue lied in a completely different place. The thing is, I also put an ApplicationContent above both of these forms. 3rd party apps require urlpatterns defined, and the docs use class-based view (ListView) in the app urls.

    When 3rd party app is defined this way, it actually tries to accept post requests, but fails to do so - the code in mixins module raises django.http.response.HttpResponseNotAllowed, preventing other content types from processing POST request (since http responses short circuit the execution, as you mentioned)

    My solution to this particular problem was simple - I made a child class of ListView with an empty post() method, like so:

    class CustomizedListView(ListView):
        # ... your code here
        def post(self, request, **kwargs):
            return True
    

    This prevents ApplicationContent instances from raising HttpResponseNotAllowed on POST requests: they return True instead, and let your process it in the other content types present on your page.


    Now, back to the forms: yes, you can easily solve this problem if you assign a unique name attribute for submit buttons per each type of your CT Form:

    <button type="submit" name="ct_form_type" value="Submit" id="form_id" class="btn btn-success">
    Submit
    </button>
    

    Then the process() method of each content type form should be implemented like so:

    def process(self, request, **kwargs):
        if request.method == 'POST':
            if not 'ct_form_type' in request.POST: return True
            # ...
    

    In other words, we check that we stumbled across the right handler before processing the form itself. If this is the wrong handler, we return True, giving other content types a chance to process POST. If neither of content types handles POST, 405 status code is returned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions