Django : On clicking submit button, the results are not showing up on the same page.

Submitted 3 years, 6 months ago
Ticket #190
Views 788
Language/Framework Django
Priority Urgent
Status Closed

Hi everyone,

I have a simple form with checkboxes and a submit button upon clicking, the results show up fine on a different page. I have made changes to make the results show up on the same page (below button) but for some reason, the results don't show up when I want it to show up on the same page. I am not able to figure out what is wrong here because the code seems fine. Any help is appreciated.

Please refer to the code below:

#template - homepage.html
<form method="GET" action="{% url 'book:homepage.html' %}">
            {{ genre_form }}
            {{ author_form }}
<button type="submit" class="btn btn-primary btn-md submitB">FILTER IT</button>
</form>

#output in the template
{% for post in posts %}
    {{ post }}
{% endfor %}

#views.py
@require_http_methods(["GET"])
  def search_results_view(request):
  genre_choices = request.GET.getlist("genre_choices")
  author_choices = request.GET.getlist("author_choices")
  posts = Post.objects.all()
   if genre_choices:
    posts = posts.filter(genresidin=genre_choices)
   if author_choices:
    posts = posts.filter(authoridin=author_choices)
   return render(request, 'homepage.html',{'posts': posts})

#urls.py
app_name = 'book'
urlpatterns = [
path('', views.homepage, name='homepage'),
path('results/', search_view, name='post-search-results'),#ignore
path('search/', SearchResultsView.as_view(), name='search_results'), #ignore
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Thanks in advance. Any help is appreciated. It is kind of urgent.

Updated Code mentioned below:

#views.py

#views.py

def homepage(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    genre = Genre.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    authors = Author.objects.filter(published_date__lte=timezone.now()).order_by('published_date')

    genre_form= GenreForm()
    author_form = AuthorForm()
 
    return render(request, 'homepage.html', {'posts': posts, 'genre': genre, 'authors': authors, 'genre_form': genre_form,'author_form': author_form})

def search_results_view(request):
    if request.method == "POST":
        genre_choices = request.POST.get("genre_choices")
        author_choices = request.POST.get("author_choices")
        posts = Post.objects.all()
        if genre_choices:
            posts = posts.filter(genre__id__in=genre_choices)
        if author_choices:
            posts = posts.filter(author__id__in=author_choices)
        print(posts)     
        return render(request, 'homepage.html',{'posts': posts})
    else:
        posts = Post.objects.all() # all posts without filtering.
        print(posts)
        return render(request, 'homepage.html',{'posts': posts})

#homepage.html
 <form method="POST" action=" ">
                {% csrf_token %}
                {{ genre_form }}
                {{ author_form }}
</form>

#output in template
{% for post in posts %}    
   {{ post }}
{% endfor %}

Above is the updated code for reference. urls.py remains the same. Really appreciate your time in helping me with this.

Another update: terminal log shows the posts (print(posts) only when I mention a different webpage like below:

return render(request, 'post-search-results.html',{'posts': posts})

if I add homepage.html instead of 'post-search-results'.html in the above code, the terminal does not print anything. Not sure what is wrong but something is wrong.

UPDATE: Added complete views.py

Submitted on Oct 03, 20
me

Are you getting any error when you try to show on same page? - scott 3 years, 6 months ago

No, I am not getting any error but it do seem like it is getting redirected to the same page because the link changes to the choice I make ex:- genre=1&author=2 (like this) but the output does not show up. That is the only problem here I guess. - me 3 years, 6 months ago
add a comment

3 Answers

Hey, I think you are looking for form submission redirect to same form page again. If my understanding is correct , then please check the approach if it helps,

#Added by scott
from django.http import HttpResponseRedirect


def search_results_view(request):
	if request.method == 'POST':
		#do what ever the logic you want
		# here is the trick for redirect to same page
		return HttpResponseRedirect(request.path_info) #Added by scott
	else:
		# do the regular GET request for the page and list the details
		genre_choices = request.GET.getlist("genre_choices")
		author_choices = request.GET.getlist("author_choices")
		posts = Post.objects.all()
		if genre_choices:
		posts = posts.filter(genresidin=genre_choices)
		if author_choices:
		posts = posts.filter(authoridin=author_choices)
		return render(request, 'homepage.html',{'posts': posts})

If this is something you are not looking, then provide more details, then i can update my answer

In case If we change the form request to POST method

def search_results_view(request):
    genre_choices=request.POST.get('some choice field')     
	if genre_choices:	
		posts.filter(genresidin=genre_choices)
		return render_to_response('homepage.html',{'posts': posts})

    return render(request, 'homepage.html',{'posts': posts})

Note: I havent tested the code. But it should be the skeleton

Submitted 3 years, 6 months ago

This is what I am looking for but unfortunately, it is still not working. I did exactly as you mentioned. The choices in checkboxes I am making can be seen in the url which means it is getting submitted but for some reason the filtered out output(according to checkbox choices) is not showing up on the same page but does show up perfectly if I redirect to a different page. Very weird. Could you please tell me what more code do you want?

Appreciate the help.

- me 3 years, 6 months ago

ok when you click on filter button which view you want to trigger and let me know you are looking only for GET request mean then you can completely ignore the POST method in my view. One more thing I have noticed, I have used POST request which is something is wrong because as you restricted only for GET request. And one more thing, in your form action URL you have provided the different view but looks like logic in view in different. Can you double check.?

- scott 3 years, 6 months ago

or Change to POST request and update code something like and I have edited my answer

- scott 3 years, 6 months ago

When I click on the filter button I want to trigger "search_results_view" and want the #output in the template (pls refer from the question) to be shown in a div under the button. Since you have mentioned to completely ignore the POST method in your view, I have gone ahead and went back to my old view itself.

Regarding the difference in views inform action URL and logic in view, both are the same "blog:homepage.html". I also tried by keeping form action to blank " " but it is not working still.

Please Note - I can see all the results if I redirect to a different page like I already told you with the same code. With the code I currently have, as I said above, it seems like it is redirecting perfectly to the homepage itself but the filtered out results are not showing up. Perhaps something to do in views.py?

Thanks a lot

- me 3 years, 6 months ago

Updated my answer, may be try that.

- scott 3 years, 6 months ago

Thank you, Scott, let me try that as well, and will get back to you.

- me 3 years, 6 months ago

what data you are getting after you added the POST logic in your code?
Share your code and also try *print(posts) * and check whether you are getting the data in your terminal if you are not getting the data in terminal, then problem in data queryset.

- scott 3 years, 6 months ago

Hi Scott, I did like you mentioned and It seems like I figured out where the problem lies. Weirdly when used "print(posts)" in both my if and else conditions and when I put my "return render(request, 'post-search-results.html',{'posts': posts})" to a different webpage, the terminal shows the posts but when I put homepage.html under render, it does not show anything. Any advice?

- me 3 years, 6 months ago

I have posted the updated code @scott @Harmandeep

- me 3 years, 6 months ago

just to confirm , you need to use POST.get
if request.method == "POST": genre_choices = request.POST.get("genre_choices") author_choices = request.POST.get("author_choices") posts = Post.objects.all()
Basically when form submit then just check request.method == POST receiving that choices or not using print statement. If data is coming in POST response, then it would defintely will render the data in your html.

- scott 3 years, 6 months ago

Thank You. I did the same and the data is still not showing up on the HTML. The print(posts) does not show up when I want to show the output on the homepage(which means the function or the form is not working?). When I mention any other page, everything works great, the print statement shows the posts and the output also shows up.

I was wondering if I can use AJAX or something to render a different page (the page where it works) under a div in the homepage.html? I think i don't have any other option. I am not able to understand why this isn't working.

- me 3 years, 6 months ago

@scott - I have added my entire views.py

- me 3 years, 6 months ago

Hey I think you need to send your form action to search_result_view . In your form action just add to send the form request to your search_view_result

- Vengat 3 years, 6 months ago


Verified

Hey, I think you need to change the logic a little. Actually, you don't need to redirect but you need to render with that data. Here are a couple of things that you should fix.

  • Change the form method to POST since we are sending the data and GET method is not that secure.
  • Implement the POST method to handle the cases.
#template - homepage.html
<form method="POST" action="{% url 'book:homepage.html' %}">  #change to POST
            {{ genre_form }}
            {{ author_form }}
<button type="submit" class="btn btn-primary btn-md submitB">FILTER IT</button>
</form>

#output in the template

   {% for post in posts %}
       {{ post }}
   {% endfor %}



#views.py
@require_http_methods(["GET"])
  def search_results_view(request):
      if request.method == "POST":
          genre_choices = request.POST.getlist("genre_choices") #Similary change to post 
          author_choices = request.POST.getlist("author_choices") # same
          posts = Post.objects.all()
          if genre_choices:
              posts = posts.filter(genresidin=genre_choices)
          if author_choices:
              posts = posts.filter(authoridin=author_choices)

          # filtered posts        
          return render(request, 'homepage.html',{'posts': posts})

      else:
          # GET request will only work if we loaded the page for the first time.

          #Comment out this line if you don't want to view posts at the start
          posts = Post.objects.all() # all posts without filtering.
          return render(request, 'homepage.html',{'posts': posts})

#urls.py
app_name = 'book'
urlpatterns = [
path('', views.homepage, name='homepage'),
path('results/', search_view, name='post-search-results'),#ignore
path('search/', SearchResultsView.as_view(), name='search_results'), #ignore
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Submitted 3 years, 6 months ago

Thank you Harman for the answer. I tried your solution and now I am receiving CSRF token missing error ( i did added {% csrf_token %} to my template) but not sure what is wrong. I also added "return render(request, 'homepage.html',{'posts': posts}, RequestContext(request))".

I am getting the below mentioned error :

Reason given for failure:

CSRF token missing or incorrect.

In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:

Your browser is accepting cookies. The view function passes a request to the template's render method. In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL. If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data. The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login.

Any suggestion is appreciated.

- me 3 years, 6 months ago

Update to the above :

I commented out 'django.middleware.csrf.CsrfViewMiddleware' from settings.py and the site works fine but still, there is no filtered-out output for some weird reason. Moreover, now, I don't see the selections I make(from checkboxes) on the URL. Any suggestions?

- me 3 years, 6 months ago

have you tried removing the decorator @require_http_methods? I'm not sure that will help or not but you can give it a try.

- harmandeep 3 years, 6 months ago

Yes, the POST method is a secure method and it doesn't show the data being sent into the URL. GET on the other hand reveals data that can be sensitive like username and passwords. For that reason, POST is the suggested option when sending form data.

- harmandeep 3 years, 6 months ago

Alright, thanks for that. But unfortunately, no output is being displayed still. If you dont mind, do you have any more suggestions? Do you want me to provide more information?

- me 3 years, 6 months ago

Have you tested your Code that you are using for filtering of the data? Does that actually filter? and what is the posts value inside the POST method?

- harmandeep 3 years, 6 months ago

Btw, I also checked by redirecting to a different page, now all posts are showing up instead of filtered out ones after the logic you have shared. Not sure what is happening.

Update : Yes, the code works great(the one I had) but ONLY when the output is shown on a different page. No data gets displayed when output is shown on the same page.

- me 3 years, 6 months ago

I am new Django actually (coming from a front-end environment). It does actually filter but only when it is being redirected to a different page.

- me 3 years, 6 months ago

What is the exact requirement you want to show? If I'm not wrong first you want to load the form without any posts and then on form submission, you want to get the data in the Template. Right?

- harmandeep 3 years, 6 months ago

Exactly. That is exactly what I want and I am able to achieve it with the code I wrote in the question I asked here but it does not show up when being called on the same page for some weird reason. Thanks

- me 3 years, 6 months ago

try updating the action in form to action="" and return render(request, 'homepage.html') in the else block

- harmandeep 3 years, 6 months ago

Thanks, Harman but even this is not working, unfortunately :(

- me 3 years, 6 months ago

@Me, I would suggest you to provide updated code link to Techions. So that it would be easy for them to guide you and close the issue at the earliest.

- Vengat 3 years, 6 months ago

@harmann, I tried to add print(posts) under both conditions if and else and when I am rendering to a different webpage, it is showing the posts under my terminal but only when i add my homepage.html to the render it does not show. Where do you think the error lies now?

- me 3 years, 6 months ago

Thanks @Aruntck, I will do that.

- me 3 years, 6 months ago

the code has been updated. Hope to get this resolved :)

- me 3 years, 6 months ago

Send the google meet link to singh.hrmn98@gmail.com if you want me to go through your code and resolve this issue.

- harmandeep 3 years, 6 months ago

@Me can you confirm your ticket status to techions to move forward?

- Vengat 3 years, 6 months ago

As we havent get any update on this ticket from user. SME's will choose the verified answer and close the ticket

- Vengat 3 years, 6 months ago

I'm not sure that will help or not but you can give it a try......

Add a hidden input for the checkbox with a different ID:

<input id='testName' type='checkbox' value='Yes' name='testName'>
<input id='testNameHidden' type='hidden' value='No' name='testName'>

Before submitting the form, disable the hidden input based on the checked condition:

if(document.getElementById("testName").checked) {
    document.getElementById('testNameHidden').disabled = true;
}

Submitted 3 years, 6 months ago


Latest Blogs