Django: dynamic url via submit button - django

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.

Related

Django : I want another web page to load inside a div

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.

Change how GET url is displayed

Summary: If I search 'apple', the url will be http://127.0.0.1:8000/search_results?csrfmiddlewaretoken=rlUwb5Ju3Xr585FarH5eAGQJtpog83hqW4wRysbsMWM6eiO3prcKRONY28N118gR&query=apple&button= and I just want to know if there is a way to change this to something cleaner like 127.0.0.1:8000/search_results/apple?
Here is my code:
urls.py
path('search_results', views.search_results, name = 'search_results'),
html:
<form action="{% url 'search_results' %}" method="GET">
{% csrf_token %}
<input name = 'query' type = 'text'/>
<button type="submit" name="button">Search</button>
</form>
and views.py:
def search_results(request):
query =request.GET.get('query')
return HttpResponse(query)
I had tried to change these 3 lines in their respective files:
`path('search_results/<str:query>')`, # thought this would achieve /search_results/apple url
<form action="{% url 'search_results' 'query' %}" method="GET">
def search_results(request, query):
but this did not work. Does anyone know how I can achieve this?
The GET parameters are encoded in the query string [wiki]. The query string is not part of the path. There is thus no way to encode this that way. But you can indeed make a "redirect view" that moves it to the path.
You can change the redirect to:
# app/views.py
from django.shortcuts import redirect
def search_redir(request):
query =request.GET.get('query')
return redirect('search_results', query=query)
def search_results(request, query):
# …
pass
In your urls.py, you then define two views: one that will "catch" the initial GET request with the querystring, and one where you move the query to the path:
# app/urls.py
from django.urls import path
urlpatterns = [
path('search_results/', views.search_redir, name='search_redir'),
path('search_results/<str:query>/', views.search_results, name='search_results'),
]
In your form however, you still use the redirect view. Note that since you perform a GET request you do not need to use the {% csrf_token %}:
<form action="{% url 'search_redir' %}" method="GET">
<input name="query" type ="text"/>
<button type="submit" name="button">Search</button>
</form>

Proper way to handle multiple Django forms in one page with two views?

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 %}

Search user by username and redirect to the user page in Django

I am working on a Django project, and now I am building a search form with which I can look up users by their id.
In the search page template, I have this:
<form action="??" method="post">
{% csrf_token %}
<ul><p>User ID<input type="text" name="uid" size="20" maxlength="40"/>
<input type="submit" name="submit" value="Search" /></p></ul></form>
In views.py:
def user_by_id(request, uid):
get_user_by_id = User.objects.get(pk=uid)
template = loader.get_template('user_search_result.html')
context = RequestContext(request, {
'q1': get_user_by_id,
})
return HttpResponse(template.render(context))
Right now I have individual pages for users ready, that have the url /users/uid(pk). What should I choose for the form action in the template that I left as ?? above? Also, what would I need to write in urls.py?
My main urls.py is:
url(r'^users/', include('users.urls', namespace="users"))
and then users/urls.py for individual profile pages is:
url(r'^(?P<uid>\d+)/$', views.profile_page, name='profile_page')
You can't pass the result of a form in the URL. The form will send it as part of the GET or POST variables, so your view needs to get it from there rather than from a URL parameter.
So, your view needs to be:
def user_by_id(request):
uid = request.GET['uid']
...etc...
and your urls.py is
url(r'^user_by_id/$', user_by_id, name="user_by_id")
and your form is:
<form action="{% url 'user_by_id' %}" method="GET">
(note I've changed the method from POST to GET, because you're not changing information in the database, you're simply requesting to view something).

Can't make class-based RedirectView work

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)