Agree.

I understood that the discussion already turned to /"//If it is deprecated, then the question that arises naturally is "What would be the proper/new way of doing it?"//"/.

Also, to clarify:

What I wrote wasn't trying to impose a particular solution. I was just hoping to point out the challenges involved.

LP,
Jure

On 20/11/2019 02:17, Matemática A3K wrote:


On Tue, Nov 19, 2019 at 9:20 PM Matemática A3K <[email protected] <mailto:[email protected]>> wrote:



    On Tue, Nov 19, 2019 at 1:29 PM Jure Erznožnik
    <[email protected] <mailto:[email protected]>> wrote:

        Sorry for barging in like this, but this is actually a problem
        I have been dealing with quite a bit lately, so:

        In my work I very often have to decide, depending on what's
        calling, what the rendered output might be. Ultimately I went
        with DRF and its content negotiation, though even that one -
        as implemented - sometimes isn't sufficient.

        See, the problem sometimes isn't that you request JSON and
        then get JSON, request HTML and get HTML.

    I think content negotiation is about giving the option to request
    the content in different formats, not rendering different content
    based on which format is requested.

        You also have to cater for exceptions. Maybe a 4xx would
        return additional objects to insert into the DOM while a 200
        would be fine with a JSON or even without data. What about 500?

    This (and below) is about how to design a particular API for your
    needs, I think it is out of the scope of the problem discussed.
    The problem discussed is that is_ajax is not a reliable way to
    determine the origin of a request (and then format the content of
    a response)


(let me try to expand myself a bit so we can refocus)

If it is deprecated, then the question that arises naturally is "What would be the proper/new way of doing it?" because it is a pattern that have been applied previously (i.e. https://docs.djangoproject.com/en/2.2/topics/class-based-views/generic-editing/#ajax-example), then decorators have been proposed and refactors.

It seems to me that if there is no reliable way of determining it from the back-end side, then in the end it will be a convention between the front and the back. This could be a GET parameter, a "ClientWants: JSONOrNothing" header, or whatever convention you like to make, but not rely on a convention which seems to be fading out.

You can ensure the actual convention by setting the header manually (as stated in the is_ajax doc) - as you do with the CSRF token. Another convention could be better (i.e. "accepts json")

So far, is what the discussion went through to my understanding :)

        I'm currently handling this with custom headers and the caller
        (the browser) tells the server what kind of outputs it can
        handle in different types of output.

        The server then performs the branching at certain code points,
        specifically the ones mentioned above. DRF allows me to choose
        the appropriate renderer. Though I should mention here, that
        the data is already serialised at that point: sometimes this
        creates issues for renderers that might desire more
        information to do their work. Just mentioning that render
        stages need to be accounted for too. This may not be a problem
        for core Django as it doesn't have stages.

        Again, sorry, but still hoping this helped in some way.

        LP,
        Jure


        On 19/11/2019 01:06, Matemática A3K wrote:

        I agree with Adam that it should be deprecated with no
        replacement.

        The content negotiation is something that should be in but
        not as a replacement of it, as a general improvement.

        I think there shouldn't be a replacement because "is_ajax"
        asks whether it came from a ""regular"" browser instead of
        jQuery and with the content negotiation you ask if the
        requester accepts a type - which can also lead to errors
        because the client may also accept other types (no example
        coming to my mind), and if so, it will lead to undesired
        behavior.

        The right approach would be making AJAX requests request JSON
        output explicitly, by using a dedicated endpoint or by
        appending something that manifests their intention - like in
        
https://docs.djangoproject.com/en/2.2/topics/class-based-views/mixins/#more-than-just-html
        is done with a get parameter. Not decide the response type by
        where it came from as it is unreliable as stated before, it
        provides convenience in some use cases but can lead to errors.

        Seems better to me to refactor the view code so you can write
        a different view for Ajax requests that returns a JSON
        without code duplication.

        As a shortcut, something like "For simple AJAX endpoints wrap
        your view with (something like) a "jsonview" decorator which
        will check the accept header (with something like Claude's
        code), return the appropriate error code if not, set the
        response type accordingly, and you should return a dict of
        strings (you have to take care of the serialization, i.e with
        
https://docs.djangoproject.com/en/2.2/topics/serialization/#serialization-formats-json).


        On Mon, Nov 18, 2019 at 3:28 PM Tom Forbes <[email protected]
        <mailto:[email protected]>> wrote:

            What I meant by that is it’s not an approach that scales
            well to lots of views. It might be better to have
            separate endpoints to return JSON (e.g adding a /json
            suffix), and in the past this has made services I’ve
            worked on a lot more maintainable and easy to understand.
            But it’s not as quick to do as `if request.is_ajax()` and
            requires a bit more upfront work. If you find you need to
            do this a lot then maybe something more structured like
            Django Rest Framework will be a better choice, which also
            handles content negotiation really well (it can produce
            XML, CSV, JSON, etc etc).


            On 18 Nov 2019, at 15:18, Matthew Pava
            <[email protected] <mailto:[email protected]>> wrote:

            “In my opinion there are not many good reasons to have
            to change behaviour if a request is made via XHR. I
            think the most common usage is to have a single view
            that returns a JSON response or a HTML response
            depending on if XHR is used
            (https://github.com/search?l=Python&q=request.is_ajax&type=Code),
            which isn’t great and isn’t reliable.”
            I do this. What would the best way to handle this?
            Perhaps the proper practice should be documented when it
            is deprecated?
            *From:*[email protected]
            <mailto:[email protected]>
            [mailto:[email protected]]*On Behalf
            Of*Tom Forbes
            *Sent:*Saturday, November 16, 2019 10:16 AM
            *To:*[email protected]
            <mailto:[email protected]>
            *Subject:*Re: Deprecate HttpRequest.is_ajax
            I would agree. Flask has done the same:
            |DeprecationWarning: Request.is_xhr is deprecated. Given
            that the X-Requested-With header is not a part of any
            spec, it is not reliable|
            In my opinion there are not many good reasons to have to
            change behaviour if a request is made via XHR. I think
            the most common usage is to have a single view that
            returns a JSON response or a HTML response depending on
            if XHR is used
            (https://github.com/search?l=Python&q=request.is_ajax&type=Code),
            which isn’t great and isn’t reliable.


            On 16 Nov 2019, at 16:08, Adam Johnson <[email protected]
            <mailto:[email protected]>> wrote:
            Django's HttpRequest.is_ajax method determines whether
            the request was made with the JS API
            
XMLHttpRequesthttps://docs.djangoproject.com/en/2.2/ref/request-response/#django.http.HttpRequest.is_ajax.
            It does so by checking the X-Requested-With header.
            The new way of making "AJAX" requests from the browser
            is the JavaScript fetch() API
            :https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API.
            I think the is_ajax() documentation is at least a little
            misleading in pretending XMLHttpRequest is the only JS
            API. There also aren't any special headers set by
            fetch() so it's not possible to detect its requests.
            I propose deprecating is_ajax() with no replacement.
            Thoughts?

            --
            Adam
            --
            You received this message because you are subscribed to
            the Google Groups "Django developers (Contributions to
            Django itself)" group.
            To unsubscribe from this group and stop receiving emails
            from it, send an email
            [email protected]
            <mailto:[email protected]>.
            To view this discussion on the web
            
visithttps://groups.google.com/d/msgid/django-developers/CAMyDDM0i-p0ZxBj-fSheGs-2pMXH7K7Oka%3DCjy1YXx-emBu3mw%40mail.gmail.com
            
<https://groups.google.com/d/msgid/django-developers/CAMyDDM0i-p0ZxBj-fSheGs-2pMXH7K7Oka%3DCjy1YXx-emBu3mw%40mail.gmail.com?utm_medium=email&utm_source=footer>.
            --
            You received this message because you are subscribed to
            the Google Groups "Django developers (Contributions to
            Django itself)" group.
            To unsubscribe from this group and stop receiving emails
            from it, send an email
            [email protected]
            <mailto:[email protected]>.
            To view this discussion on the web
            
visithttps://groups.google.com/d/msgid/django-developers/84DCD242-69A8-4B8D-9EB6-243312B5F77F%40tomforb.es
            
<https://groups.google.com/d/msgid/django-developers/84DCD242-69A8-4B8D-9EB6-243312B5F77F%40tomforb.es?utm_medium=email&utm_source=footer>.

            --
            You received this message because you are subscribed to
            the Google Groups "Django developers (Contributions to
            Django itself)" group.
            To unsubscribe from this group and stop receiving emails
            from it, send an email
            [email protected]
            <mailto:[email protected]>.
            To view this discussion on the web
            
visithttps://groups.google.com/d/msgid/django-developers/cb12b0005c5e4191be3a97d0d2c44cc5%40iss2.ISS.LOCAL
            
<https://groups.google.com/d/msgid/django-developers/cb12b0005c5e4191be3a97d0d2c44cc5%40iss2.ISS.LOCAL?utm_medium=email&utm_source=footer>.

-- You received this message because you are subscribed to
            the Google Groups "Django developers (Contributions to
            Django itself)" group.
            To unsubscribe from this group and stop receiving emails
            from it, send an email to
            [email protected]
            <mailto:[email protected]>.
            To view this discussion on the web visit
            
https://groups.google.com/d/msgid/django-developers/DA72EC9C-AE24-4C04-854A-A6E19DD64132%40tomforb.es
            
<https://groups.google.com/d/msgid/django-developers/DA72EC9C-AE24-4C04-854A-A6E19DD64132%40tomforb.es?utm_medium=email&utm_source=footer>.

-- You received this message because you are subscribed to the
        Google Groups "Django developers (Contributions to Django
        itself)" group.
        To unsubscribe from this group and stop receiving emails from
        it, send an email to
        [email protected]
        <mailto:[email protected]>.
        To view this discussion on the web visit
        
https://groups.google.com/d/msgid/django-developers/CA%2BFDnh%2B5xr1fWteL6bh2NhF0yJV%3DPwyvhkiLYyPmGO23q0sZ9w%40mail.gmail.com
        
<https://groups.google.com/d/msgid/django-developers/CA%2BFDnh%2B5xr1fWteL6bh2NhF0yJV%3DPwyvhkiLYyPmGO23q0sZ9w%40mail.gmail.com?utm_medium=email&utm_source=footer>.
-- You received this message because you are subscribed to the
        Google Groups "Django developers (Contributions to Django
        itself)" group.
        To unsubscribe from this group and stop receiving emails from
        it, send an email to
        [email protected]
        <mailto:[email protected]>.
        To view this discussion on the web visit
        
https://groups.google.com/d/msgid/django-developers/0174a0b6-3a32-5339-9ae9-31050d2d2aaf%40gmail.com
        
<https://groups.google.com/d/msgid/django-developers/0174a0b6-3a32-5339-9ae9-31050d2d2aaf%40gmail.com?utm_medium=email&utm_source=footer>.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected] <mailto:[email protected]>. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CA%2BFDnhKT0ST76G5T6qFz7NWuhnuwoQvqQ3RRHZcFWhyV1jO1sQ%40mail.gmail.com <https://groups.google.com/d/msgid/django-developers/CA%2BFDnhKT0ST76G5T6qFz7NWuhnuwoQvqQ3RRHZcFWhyV1jO1sQ%40mail.gmail.com?utm_medium=email&utm_source=footer>.

--
You received this message because you are subscribed to the Google Groups "Django 
developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/260544c2-1dcd-c38f-c267-e4941d1f5088%40gmail.com.

Reply via email to