I am new to Django and I have a simple submit button that is clicked after selecting multiple options in checkboxes. Upon clicking the results show up on a different page. I want the results to show up on the same page itself(below the submit button let's say) or maybe inside a div below the submit button.
Below is the code for your reference:
#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>
#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(genres__id__in=genre_choices)
if author_choices:
posts = posts.filter(author__id__in=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)
I hope this bit of information will be useful. Right now, the functionality works great but the results show up on a different page. I want the results to show up on the homepage itself and the above code is what I tried but it is not working.
Please help.
Update : As asked, I have added the output in the homepage itself(where I want the result to be but still its not helping)
{% for post in posts %}
{{ post }}
{% endfor %}
Your code looks fine! always provide the frontend part where you are passing the data from your views. That might be the problem, use the dictionary posts that you have mentioned here in your views to your (frontend) part. You might be using that posts elsewhere in the project that's why it renders it to that page.
Related
I was doing the Python Crash Course Ex. 19-1: Blogs, and I'm now stuck at saving the edit of any blog. I tried plugging in the .errors code in the blog.html (for showing each blog) but it shows nothing, so I guess my templates has no field errors (?)
Here're some codes I believe crucial for solving the not-saving-the-edit problem. The new_blog function in views.py works fine so I'll skip it.
The edit_blog function in views.py:
def edit_blog(request, blog_id):
idk = BlogPost.objects.get(id = blog_id)
if request.method != "POST":
form = BlogForm(instance = idk)
else:
form = BlogForm(instance = idk, data = request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('blogs:blogs'))
content = {"editing_blog": form, "psst": idk}
return render(request, 'blogs/edit_blog.html', content)
new_blog.html:
{% extends "blogs/all.html" %}
{% block content %}
<p>Write a new blog:</p>
<form action="{% url 'blogs:new_blog' %}" method='post'>
{% csrf_token %}
<table border="1">
{{ new_blog }}
</table>
<p></p>
<button name="submit">Submit</button>
</form>
{% endblock content %}
edit_blog.html:
{% extends "blogs/all.html" %}
{% block content %}
<p>Edit the blog:</p>
<form action="{% url 'blogs:blog' psst.id %}" method='post'>
{% csrf_token %}
<table border="1">
{{ editing_blog }}
</table>
<p></p>
<button name="submit">Save changes</button>
</form>
{% endblock content %}
Btw, the urlpattern is here:
from django.urls import path, include
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.homepage, name = 'homepage'),
# Show all blogs.
path('blogs/', views.blogs, name = 'blogs'),
# Show the detail of a blog.
path('blogs/<int:blog_id>', views.blog, name = 'blog'),
# Page for adding a new blog.
path('new_blog/', views.new_blog, name = 'new_blog'),
# Page for editing a blog.
path('edit_blog/<int:blog_id>', views.edit_blog, name = 'edit_blog'),
]
No matter how I change the title, or content, or both of the blog I don't see the changes saved. Is it:
A) My form action in edit_blog.html goes wrong, as wakandan mentioned?
B) I need to adjust something in edit_blog view function, like Bibhas said?
Many thanks. Also tell me if I need to add more codes for understanding.
Your form action is currently set to {% url 'blogs:blog' psst.id %}, which means you're posting to your views.blog view, which is just a detail view. You need to change the action to {% url 'blogs:edit_blog' psst.id %} so that the form is posted to your edit view.
It's not clear from the code you have posted where the editing_blog context variable is coming from - you will need to make sure that this is an instance of the same form that your edit view is looking for, otherwise you'll run into other problems.
Finally also note that you are not currently handling the case where the form has errors - i.e., there is no else condition specified for form.is_valid().
I want to use a dynamical url with Django for a search option in my database. I implemented an input text field for my search term and a submit button to start the query. So, when I click the button the new url of my search result should include the term from the text field (written by the user).
How can I implement a dynamic url using a submit button instead of a hyperlink? How do I get the value of my text field into my url? Can you please help me?
That is part of my (non-working) code:
urls.py
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^search/(?P<term>\w{2}_[0-9.]+)/$', views.search, name='search'),)
views.py
def search(request, term ):
search_term = request.GET['term']
#generate results for search_term
return render(request, 'app/results.html', {'list_of_r': list_of_r})
results.html
<form action="{% url 'app:search/{{term}}' %}" method="get">
{% csrf_token %}
<input id="text_id" type="text" name="term" maxlength="20" />
<input type="submit" value="submit" name="submit"/>
</form>
That is not how you do forms: but you don't need to. The GET request submitted by the form automatically includes the parameters in the form, that's the whole point: so if you submitted to the path /search, with the value "text_to_be_searched" in your term field, the URL woudl be "/search?term=text_to_be_searched". You don't need to do anything else.
I've struggled with this problem for the last two days and could use some help. The home page for my Django 1.6 application will include two forms, one that a user can use to sign in to the site and one they can use to sign up (create a login) for the site:
# templates/home/home_page.html
<div class="sign-in-form">
<form action="{% url 'apps.home.views.sign_in' %}" method="post">
{% csrf_token %}
{{ sign_in_form.as_p }}
{% if next %}
<input type="hidden" name="next" value="{{ next }}">
{% else %}
<input type="hidden" name="next" value="{% url 'view-members' %}">
{% endif %}
<input type="submit" value="Sign in">
</form>
</div>
<div class="sign-up-form">
<fieldset>
<legend>Sign up</legend>
<form action="{% url 'apps.home.views.sign_up' %}" method="post">
{% csrf_token %}
{{ sign_up_form.as_p}}
<p><input type="submit" value="Sign up" /></p>
</form>
</fieldset>
</div>
If the user submits, the sign_in form, they'll be taken to a page where they can view other site members. If they submit the sign_up form, they'll be taken to a second signup page where they'll create a user profile, etc.
Originally, I was going to use the technique shown in this question and use one view to handle the homepage. However, I decided to try to use two views because I'm using the Django's actual login view (django.contrib.auth.views.login) so that I can add code to it to detect the user's device (phone, tablet, or computer), and merging that view with my sign_up view would create a very long and complicated view to maintain. I'd prefer to keep the views for both forms separate.
Here's the home page and sign_in views:
# apps/home/views:
def home_page(request, template):
sign_in_form = SignInAuthenticationForm()
sign_up_form = CreateAccountForm()
return render(request, template, {"sign_in_form": sign_in_form,
"sign_up_form": sign_up_form})
#sensitive_post_parameters()
#csrf_protect
#never_cache
def sign_in(request,
template='home_page.html',
redirect_field_name=REDIRECT_FIELD_NAME,
# authentication_form=AuthenticationForm,
authentication_form=SignInAuthenticationForm,
current_app=None, extra_context=None):
# Do device detection here...
# django.contrib.auth.views code goes here...
return response
The signup view will just be your typical, function-based view for processing a form as described in the Django documentation.
What I'm struggling with is my URLconf files. Here's my main and "home" URLconf files:
# conf/urls.py
urlpatterns = patterns('',
url(r'^$', include('apps.home.urls')),
# Other url patterns...
)
# apps/home/urls.py
urlpatterns = patterns('apps.home.views',
url(r'^$',
'home_page',
{'template': 'home/home_page.html'},
name='home-page'),
url(r'^sign_in/$',
'sign_in',
{'template': 'home/home_page.html'},
name='sign-in'),
url(r'^sign_up/$',
'sign_up',
{'template': 'home/home_page.html'},
name='sign-up'),
)
The problem is that I get this error during template rendering:
NoReverseMatch at /
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Request Method: GET
Request URL: http://localhost:8000/
Django Version: 1.6.2
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Exception Location: /Users/smith/venv/swing/lib/python2.7/site-packages/django/core/urlresolvers.py in _reverse_with_prefix, line 429
Python Executable: /Users/smith/venv/swing/bin/python
Python Version: 2.7.5
Python Path:
['/Users/smith/Dropbox/www/swing',
'/Users/smith/venv/swing/lib/python2.7/site-packages/wurfl_cloud-1.0.1-py2.7.egg',
'/Users/smith/venv/swing/lib/python27.zip',
'/Users/smith/venv/swing/lib/python2.7',
'/Users/smith/venv/swing/lib/python2.7/plat-darwin',
'/Users/smith/venv/swing/lib/python2.7/plat-mac',
'/Users/smith/venv/swing/lib/python2.7/plat-mac/lib-scriptpackages',
'/Users/smith/venv/swing/Extras/lib/python',
'/Users/smith/venv/swing/lib/python2.7/lib-tk',
'/Users/smith/venv/swing/lib/python2.7/lib-old',
'/Users/smith/venv/swing/lib/python2.7/lib-dynload',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/Users/smith/venv/swing/lib/python2.7/site-packages']
At first I started to think that maybe it's telling me that it can's find the correct URL pattern in my home/urls.py file because the URL signature in my form is incorrect. Maybe I needed to do this to match the arguments in the sign_in view:
<form action="{% url 'apps.home.views.sign_in' 'home/home_page.html' %}" method="post">
But I'm already showing the template name in the home URLconf. And I don't think I need to pass the other view arguments in the form action (e.g. redirect_field_name) because their optional. In any case, adding this argument to the form action didn't fix it.
One of the things that confuses me is how to set the first url argument. I've set them to r'^sign_in/$' and r'^sign_up/$' because if I set them both to r'^$', the page will render properly but when I submit either form, it justs posts back to the home page. You can see this will happen by doing a "view source" on the page. It shows each form's action will be "/". On the other hand, the way I have it now seems incorrect to me because the site won't actually have a "/sign_in/" and "/sign_up/" URL since both forms are on the home page. Also, is there going to be a problem in which if the user submits one for or the other improperly, errors for both forms will be rendered on the page?
The Django documentation, to the best of my knowledge, doesn't really describe a standard approach for doing what I'm trying to do. It describes how to render multiple versions of the same form. Can anyone tell me what I'm doing wrong?
Thanks.
Your form names are 'sign_in_form' and 'sign_up_form', but in your html you wrote them 'form.as_p' instead of 'sign_in_form.as_p' and 'sign_up_form.as_p' this is the first bug a saw in your code.
The real problem is in your urls configuration. In your main urls.py you have
url(r'^$', include('apps.home.urls')),
Other ...
Though you will not be able to get to localhost:8000/sign_in/ because initially it does not satisfy to ^$ .
Try to change it by
url(r'', include('apps.home.urls')),
and put it to the end of urls.py.
i test this see if this what you want:
view.py
def loginUser(request,**Kargs):
LoginFormSet = formset_factory(LoginForm)
SignFormSet = formset_factory(SignForm)
if request.method == 'POST':
login_formset = LoginFormSet(request.POST, prefix='login')
sign_formset = SignFormSet(request.POST ,prefix='sign')
if login_formset.is_valid():
#do somthing
elif sign_formset.is_valid():
#do somthing
return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})
else:
login_formset = LoginFormSet(prefix='login')
sign_formset = SignFormSet(prefix='sign')
return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})
page.html:
<form action="{% url 'loginUser' %}" method="post">
{% csrf_token %}
{{ login_formset.management_form }}
{% for form in login_formset %}
{{ form }}
{% endfor %}
{{ sign_formset.management_form }}
{% for form in sign_formset %}
{{ form }}
{% endfor %}
I have made a blog with Django with articles (like so: mysite.com/a/article_id/) and would like users to be able to comment on the article's comment page (i.e: mysite.com/a/article_id/comments/)
So far I haven't had much success. It seems that the article_id in the url is blocking somehow the comments app.
This is my url.py:
from django.conf.urls import patterns, include, url
from django.contrib.auth.views import login, logout
urlpatterns = patterns('blogengine.views',
url(r'^$', 'get_posts', name='index'),
url(r'^write/', 'write_post', name='write'),
url(r'^a/(?P<post_id>\d+)/$', 'detail'),
url(r'^a/(?P<post_id>\d+)/comments/$', 'detail_comments'),
url(r'^a/(?P<post_id>\d+)/comments/', include('django.contrib.comments.urls')),
)
These are my views - views.py:
def detail_comments(request, post_id):
p = get_object_or_404(Post, pk=post_id)
return render_to_response('blogengine/detail_comments.html', {'post': p},
context_instance=RequestContext(request))
And this is my template detail_comments.html
{% block content %}
{% load comments %}
{% get_comment_form for post as form %}
<form action="/a/{{ post.id }}/comments/post/" method="post">
{% csrf_token %}
{{ form.content_type }}
{{ form.object_pk }}
{{ form.timestamp }}
{{ form.security_hash }}
<p style="display:none"><label for="id_honeypot">Leave blank</label>{{ form.honeypot }}</p>
<p>
<label for="id_comment">Comment</label>
{{ form.comment }}
</p>
<p><input type="submit" name="post" value="Post →" /></p>
</form>
{% endblock %}
(Oh and this is kind of obvious but the comments app is installed in settings.py)
If the form action is set to {% comment_form_target %}, like suggested in the docs, django throws this error:
NoReverseMatch at /a/2/comments/
Reverse for 'django.contrib.comments.views.comments.post_comment' with arguments '()' and keyword arguments '{}' not found.
I tried "hacking" my way out by replacing it with this /a/{{ post.id }}/comments/post/ which works to display the page but then if I try to post a comment, django throws a different error:
TypeError at /a/2/comments/post/
post_comment() got an unexpected keyword argument 'post_id'
Is there a way to get the comments app to ignore the id_post? Or another way to do this?
Thanks.
The error message is pretty unambiguous: django.contrib.comments.views.post_comment does not take a post_id argument, so it throws.
As the comments views do not need nor want the argument, why not just leave it out?
You should be able to modify the URL route not to capture the post_id at all (although at the cost of consistency) like so:
url(r'^a/(?:\d+)/comments/', include('django.contrib.comments.urls')),
or simply
url(r'^a/\d+/comments/', include('django.contrib.comments.urls')),
Note that there's really no point in having this kind of nesting at this point anyway if it's just going to be ignored, so you could simplify it to:
url(r'^comments/', include('django.contrib.comments.urls')),
Granted, this doesn't look as pretty and pseudo-RESTful without the vestigial prefix, but there's really no point in having it there if you're just going to ignore it.
The other thing you could do would be to wrap all the views the comments app provides so they throw a 404 if the post_id is invalid, but that seems overkill.
Ok so I solved my problem by simply doing what the docs say. I imported the comments like so:
url(r'^comments/', include('django.contrib.comments.urls')),
And kept this url pointing to my detail_comments view which displays the comment list and form:
url(r'^a/(?P<post_id>\d+)/comments/$', 'detail_comments'),
So basically the processing happens at /comments/ but the user interacts with this page: /a/post_id/comments/
The only problem I had was that the Django comments app automatically redirected the user to a success page after posting a comment.
I solved this by setting a "next" hidden field in the form indicating the current page.
I'm currently trying to migrate my function based views for the new django 1.3 class-based views. To start, I changed a simple RedirectView I had, but I cant get it to work, even worst, I can't understand how the class view works. The mechanism is simple, I have a select field in the index page, the user select an option and clicks "go". The view must get the url corresdponding to that name and redirect there.
When sending the POST signal, django doesn't return anything, just a 405 error in the terminal.
UPDATED code:
index.html
[...]
<div id="widget">
<h2>{% trans "Spaces list" %}</h2><br />
<form method="post" action="/spaces/go/">{% csrf_token %}
<select name="spaces">
{% for space in spaces %}
<option>{{ space.name }}</option>
{% empty %}
<option>{% trans "No spaces" %}</option>
{% endfor %}
</select>
<input type="submit" value="{% trans 'Go' %}" />
</form>
</div>
[...]
views.py
class GoToSpace(RedirectView):
url = "/spaces/"
def get_redirect_url(self, **kwargs):
self.place = get_object_or_404(Space, name = self.request.POST['spaces'])
return self.place.url
urls.py
from django.conf.urls.defaults import *
from e_cidadania.apps.spaces.views import GoToSpace
urlpatterns = patterns('',
(r'^go/', GoToSpace.as_view()),
)
What I am doing wrong?
You can't refer to a class-based view in urls.py just by referencing the name of the class. As is well documented, you need to call the classmethod as_view:
(r'^go/', go_to_space.as_view()),
You should really follow PEP8 and make your class name GoToSpace, which would make the difference from a function more obvious.
Also, get_redirect_url is a method, so it should have self as the first positional argument.
SOLVED:
RedirectView in django 1.3 only accepts GET requests, I was doing a POST (as recommended in django 1.2.x)
This issue was fixed for django 1.3.x (ticket #15739)