2

I have the following template file, where I am going to perform an ajax request. If I click on the show link in the template the jquery function gets executed and then I receive the following error message in the developer console of my browser:

  • TypeError at /projects/djangobook/discussions/5/show/8

  • 'NoneType' object is not callable

Traceback:

File "/Users/sebastian/Developer/Zaumdo/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)

File "/Users/sebastian/Developer/Zaumdo/lib/python2.7/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/Users/sebastian/Developer/Zaumdo/lib/python2.7/site-packages/braces/views.py" in dispatch
  107.             request, *args, **kwargs)

File "/Users/sebastian/Developer/Zaumdo/Zaumdo/core/mixins.py" in dispatch
  49.         return super(GroupAwareMixin, self).dispatch(request, *args, **kwargs)

File "/Users/sebastian/Developer/Zaumdo/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
  86.         return handler(request, *args, **kwargs)

Exception Type: TypeError at /projects/djangobook/discussions/5/show/8

Exception Value: 'NoneType' object is not callable

Request information:
GET: No GET data

POST:
name = u'sebastian'

FILES: No FILES data

COOKIES:
csrftoken = 'fWD0OojhrpTLhuxtxb2NF96rVSnKGpWy'
sessionid = 'fccuv36b538pqnulqyhbdsq7ihyrvjo5'

template.html

{% for post in object_list %}
    {{ post.creator }}
    {{ post.created }}
    {{ post.body }}
    <a href="{% groupurl post_answer group discussion_id=discussion.id pk=post.id %}">Answer</a>
    <a class="show_answers" href="{% groupurl post_show_answers group discussion_id=discussion.id post_id=post.id %}">Show</a>
{% endfor %}

<script type="text/javascript">
    $(".show_answers").click(function(e) {
        e.preventDefault();
        var self = $(this);
        ajax_req = $.ajax({
            url: self.attr("href"),
            type: "POST",
            data: {name: "sebastian"},
            success: function(ctx) {console.log(ctx);}
        });
    });
</script>

urls.py

from django.conf.urls import patterns, url

from discussions.views import DiscussionListView, DiscussionCreateView, DiscussionUpdateView,
DiscussionDeleteView, PostListView, PostCreateView, PostAnswerView

urlpatterns = patterns\
(
    'discussions.views',
    url(r'^$', DiscussionListView.as_view(), name='discussion_list'),
    url(r'^create/$', DiscussionCreateView.as_view(), name='discussion_create'),
    url(r'^update/(?P<pk>\d+)$', DiscussionUpdateView.as_view(), name='discussion_update'),
    url(r'^delete/(?P<pk>\d+)$', DiscussionDeleteView.as_view(), name='discussion_delete'),
    url(r'^(?P<discussion_id>\d+)/$', PostListView.as_view(), name='discussion'),
    url(r'^(?P<pk>\d+)/create/$', PostCreateView.as_view(), name='post_create'),
    url(r'^(?P<discussion_id>\d+)/answer/(?P<pk>\d+)', PostAnswerView.as_view(), name='post_answer'),
    url(r'^(?P<discussion_id>\d+)/show/(?P<post_id>\d+)', PostListView.as_view(), name='post_show_answers'),
)

In this view I would like to send an HttpResponse.

views.py

class PostListView(LoginRequiredMixin, GroupAwareMixin, ListView):
    model = Post
    template_name = 'discussions/discussion.html'

    discussion = None
    post = None
    posts = None

    def get_queryset(self):
        # Get the discussions from the pk in the url
        self.discussion = get_object_or_404(Discussion, pk=self.kwargs['discussion_id'])

        # return HttpResponse(json.dumps("success"), mimetype="application/json")

        # Fetch all the root posts (depth=1) in the discussion
        self.posts = self.discussion.posts.filter(depth=depth)
        return self.posts

    def get_context_data(self, **kwargs):
        context = super(PostListView, self).get_context_data(**kwargs)
        context['discussion'] = self.discussion
        return context

2 Answers 2

2

Django to send a request using ajax is necessary to generate a token as explained in the documentation csrf_token.

I develop my applications in this token as follows.

In layout.html

<html>
    <head>...</head>
    <body>
       <!--the end of the body tag -->
       {% csrf_token %}

       <script type="text/javascript">
           $tagToken = $("{% csrf_token %}");
           var CSRF_TOKEN = $tagToken.find("input[name='csrfmiddlewaretoken']").val();
       </script>
    </body>
</html>

Now in file js.

$(".show_answers").click(function(e) {
    e.preventDefault();
    var self = $(this);
    ajax_req = $.ajax({
        url: self.attr("href"),
        type: "POST",
        data: {name: "sebastian"},
        beforeSend: function(xhr, settings) {
            if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
                xhr.setRequestHeader("X-CSRFToken", CSRF_TOKEN);
            }
        },
        success: function(ctx) {console.log(ctx);}
    });
});

That would be all for you to accept the request django.

Sign up to request clarification or add additional context in comments.

2 Comments

Concerning the CSRF Protection on Ajax I added this docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax Javascript to my template. Is that enough?
to explain what is sufficient to use CSRF.
1

Exception throws on calling handler(request, *args, **kwargs) in dispatch function because your view didnt have post method:

# django.views.generic.base.py:
def dispatch(self, request, *args, **kwargs):
    # Try to dispatch to the right method; if a method doesn't exist,
    # defer to the error handler. Also defer to the error handler if the
    # request method isn't on the approved list.
    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

Your ajax post url is same as page url:

    ajax_req = $.ajax({
        url: self.attr("href"),
        ...

So, you should add post method to your view class.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.