Django to call the correct function - python

been searching a lot for fixing my issue.. New to django and might be missing a very simple logic here and looking for some help..
I have created a form in html page called thispage.html as below:
<form action="{% url 'getvaluefromform' %}" method="POST">{% csrf_token %}
<input type="text" name='mytitle' placeholder="enter title">
<input type="submit" value="save">
</form>
then I updated views.py with the below code:
from django.shortcuts import render
def index(request):
return render(request,'thispage.html')
def getvaluefromform(request):
mytitle = request.POST.get('mytitle')
print(mytitle)
return render(request,'thispage.html')
finally my urls.py has this part:
from dhango.urls import path
from . import views
urlpatterns = [
path('',views.index,name='index'),
path('getvaluefromform',views.getvaluefromform,name='getvaluefromform')
]
Problem:
when I use this I am able to get the input vallue however the url is changing to '/getvaluefromform' and when I remove 'getvaluefromform' from the url section and just keep it '' then the code view index gets picked up.
Is there a way I can call the second function when button is clicked without moving to the new path. Please advise.
P.S - I am deliberately not using a model form because I want to build a raw sql query based on user input and then run the query to get the results/ create a new table on the database.

Django forms:
If you want to get POST data from a form without changing routes you have a very good example in the official documentation.
HTML forms:
If you're not into Django forms you can do as stated below.
def getvaluefromform(request):
if request.method == 'POST':
mytitle = request.POST.get('mytitle')
return render(request,'otherpage.html')
return render(request,'thispage.html')
What this will do is basically check if there's a POST request, get the form data and if there's a GET request, you'll just render the defined page.
If you must have two different routes, I suggest using Javascript.

Related

Django - render only partial / change context / change form after POST without refresh

I need some help with django
I have kind of landing page with form, which need to have 3 different states.
Flow looks like this: enter email -> check database for user with that email -> render login or register form, still in same template.
Code looks like this:
.html
// lots of code
<form method="POST" id="form">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="send">
</form>
// lots of code
and in views.py i have render method with context
return render(
request,
'apply.html',
context,
)
where in context i placed simple standard django form like:
class ApplyForm(forms.Form):
email = forms.CharField()
phone = forms.CharField()
Is there and way to change ApplyForm to LoginForm or RegisterForm after sending POST from first one, without refreshing whole page?
I though about injecting all three forms to context, sending some ajax request, and then differentiate which form should be displayed, but I'm not sure how could it be done...
thanks in advance!

View function is not being called after submitting form in django

I have made a simple form inside a html file whose path is www.site.com/posts/5. Whenever the form is submitted, it redirects back to the same page i.e www.site.com/posts/5 displaying a message given by user in the form.
However, whenever the form is submitted it doesn't call the foobar view.
The urls.py, views.py and html files are as follows:-
urls.py
urlpatterns = [
path('posts/<int:foo>',user_views.display, name="display",
path('posts/<int:foo>',user_views.foobar, name="makefoo"),
]
views.py
def foobar(request, foo):
#do something
html file
<form name="fooform" action= "{% url 'makefoo' 5 %}" method = "post">
{% csrf_token %}
<input type="text" name="FOO_BODY" maxlength="300" required>
<input type="submit" value="comment">
<input type="reset" value="clear">
</form>
Edit : user_views is just from user import views as user_views
You can not attach two views to the same URL. The {% url ... %} template tag, only generates a URL for that path. But if there is a "url clash", then it is possible that the requests ends up in the other view.
You thus should define another URL, or encode the post logic in the display view. In case of a POST request, you can thus first take the necessary steps, and then for example return a redirect to the page, such that we can again render the page:
def display(request, foo):
if request.method == 'POST':
# do something
return redirect(display, foo=foo)
#do something else (original code)
return HttpResponse(..)
This is the famous Post/Redirect/Get web development design pattern [wiki]. This is usually better than returning a HTTP response directly in the POST, since if the user performs a refresh, the POST will be performed a second time.
As mentioned in the comment by #williem, you have two path() defined in the urls.py.
Always First matching route will be picked up from the url route table. So whenever r^'posts/' is requested it will call the display() from the user_views, so it will never go to foobar(). Either remove the route with display() or change the sequence. Also, I assume you imported the user_views.
Reference:
https://docs.djangoproject.com/en/2.1/topics/http/urls/

Django POST not calling view

I am trying to create a simple subscription form in the front page of my site. I created the view with a model form (the model contains only name and e-mail as attributes). When I go to the root address (GET) it works fine and loads the form. I then fill it with some data, click the submit button (the form action can either be set to '' or '/', the result is the same) and it redirects to the same root page, but it does not load anything, the page remains blank. In the console I can see it calling through POST method, but not even the first print of the view function gets printed.
Any ideas? I know it must be something silly, but I spent sometime in it and haven't yet found out what it could be.
In urls.py:
url(r'', FrontPage.as_view(template_name='rootsite/frontpage.html')),
In rootsite/views.py
class FrontPage(TemplateView):
'''
Front (index) page of the app, so that users can subscribe to
have create their own instance of the app
'''
template_name = 'rootsite/frontpage.html'
def get_context_data(self,
*args,
**kwargs):
c = {}
c.update(csrf(self.request))
print self.request.method
if self.request.method is 'POST':
print 'OK - POST IT IS, FINALLY'
form = NewUsersForm(self.request.POST)
print form.__dict__
if form.is_valid():
form.save()
return HttpResponseRedirect('/' + '?thanks=1')
else:
form = NewUsersForm()
return {'form':form}
You can't return a redirect from within get_context_data - it's for context data only, hence the name.
You should really be using a proper form view for this, which includes methods for redirecting after form validation.
Did you include a csrf_token in your template (as per the example here: http://www.djangobook.com/en/2.0/chapter07.html)?
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</form>
I could be wrong, but I thought Django wouldn't accept a POST request without a csrf token?

Trouble shooting Django form/view/template and how they all work together

I'm currently trying to learn Django from the book and I read most of it and am now trying to write a webapp of my own. I just really can't figure out how they all interact and how they aren't fitting together.
My urls.py file reads like this...
from django.conf.urls.defaults import patterns, include, url
from users.views import homepageview, submitted, referral_create
urlpatterns = patterns('',
(r'^$', homepageview),
(r'^submitted/$', referral_create),
the views.py file looks like this...
# Create your views here.
from django.shortcuts import render_to_response
from django import forms
from datreferral.users.forms import ReferralCode
def homepageview(request):
now = 'your damn referral code'
return render_to_response('datreferraltemplate.html', {'now': now})
def referral_create(request):
if request.method == 'POST':
form = ReferralCode(request.POST)
if form.is_valid():
new_code = form.save()
return HttpResponseRedirect(reverse(contact_details, args=(new_contact.pk,)))
else:
form = ReferralCode()
The form.py file looks like
from django import forms
class ReferralCode(forms.Form):
referralcode = forms.CharField()
and the template looks like this...
{% extends "base.html" %}
{% block title %}
Enter your referral codes!
{% endblock %}
{% block content %}
<h1>Enter your code</h1>
{% if errors %}
<ul>
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<form action="" method="POST">
<p>Subject: <input type="text" name="subject" value="{{ referralcode }}"></p>
<input type="submit" value="Submit">
</form>
{% endblock %}
Hopefully that's enough info.
I am looking for two things. First off, when I try to view the page after submitting the form i get no where because I assume that the "if request.method == 'POST':" is not triggering. Obviously its something pretty obvious but I'm in one of those modes where I can find the bug for the life of me.
The second question I have is basically is plea for help. somehow after reading through those chapters multiple times I can't seem to nail down how all of the pieces interact with each other. I know that the template and the urls.py and the views.py interact and I get (I think) but I can't really grasp how the database and forms interact with each other and with the views/templates. like say I just wanted to a simple form where whatever the use inputted is written into the database... How would you do that? I'm using postgres if that matters.
Note: the form and the in the template is a modified version of code i found on here and tried to manipulate to meet my needs but failed so don't be overly thrown off if that doesn't make sense I wasn't able to mess with that part that much yet because of these problems.
As I'm new to web development I really appreciate any one willing to help me or point me in the right direction.
You don't return anything in you else clause. A views must always return a response, which can be pretty much anything, but in most cases you will return a instance of a (sub)-class of HttpResponse (I really like the render shortcut). It is a good idea to have a default return at the bottom of you view, add some early returns for "special" responses and otherwise let the execution reach the default return - this way you never have the case where you return nothing.
You have to use a Model to save data (have you work through the tutorial?). Usually the excution model is the following:
you app gets a request and the urls.py is searched for a view that should be called
the request is passed through the middleware
you view is called and "does" something. I.e. it fetches data from the database (again using a model) or stores something in the db (or saves a uploaded file, sends a mail, etc. - aview can really do anything)
you view returns "something"
the returned "something" is passed through the middleware and will eventually be tranformed in a stream of data that is passed to the browser
Thats it. This is a bit simplified but it pretty much covers all important parts.
Well, there are quite a few things wrong here.
First is that your form is being rendered by the base view, homepageview, and is submitting back to that same URL. However the form processing logic is in a separate view, which isn't being called. Either change the action parameter of the form to point to the other URL or - better - move all the logic into the same view.
Secondly, your form processing view isn't returning a response or rendering a template. That's an error in Django, and if you had managed to call that view you would see an exception.
Thirdly, I find it hard to believe you've read the entire Django book and not seen anything about models or databases. You've got no indication here that you've set up any models, but without them Django won't write anything to a database. You'll need to do that, then change your form into a ModelForm subclass, after which you can call form.save() successfully.

The "next" parameter, redirect, django.contrib.auth.login

I'm trying to redirect users to custom url "/gallery/(username)/" after successfully logging in. It currently redirects to the default "/account/profile/" url While I know what I can override the redirect url in my settings.py, my url is dynamic thus it will not work.
Documentation states that I need to use the "next" parameter and context processors. I have the {{next}} in my template, but I'm confused on how to actually pass the "/gallery/(username)". Any help would be greatly appreciated.
p.s: I'm trying to steer away from writing my own login view.
Django's login view django.contrib.auth.views.login accepts a dictionary named extra_context. The values in the dictionary are directly passed to the template. So you can use that to set the next parameter. Once that is done, you can set a hidden field with name next and value {{ next }} so that it gets rendered in the template.
I confess I usually use 2 redirects in order to get something like this to work.
First, Make your own registration/login.html page. You can copy-and-paste the html example in this section of the authentication docs to make the process a little easier. Instead of using the dynamic '{{ next }} variable from the context, however, hardwire the value of next to go to a generic landing view of logged-in users
<input type="submit" value="login" />
<input type="hidden" name="next" value="/gallery/" />
Then, in the view that you map to the /gallery/ URL, extract the User object from the request (since the user will now be logged in, especially if the gallery view is wrapped in a #permission_required or #login_required decorator. Use that view to redirect to the appropriate user-specific gallery page:
#login_required
def gallery(request):
url = '/gallery/%s/' % request.user.username
return HttpResponseRedirect(url)
If you already have the custom template for login form you need to add the following inside your <form> tag:
<input type="hidden" name="next" value="{{next}}" />
BTW, you don't have to create your own login view. django.contrib.auth.views.login works fine. You only need to create a template for it (registration/login.html)
being an newbie to django and stumbling over this somewhat older thread i found a differing solution for the problem of dynamically (=override a custom default only if needed) setting the next-param that i'd like to share (working fine with django 1.5, earlier versions untested):
just as django-d i wanted avoid repetition and a custom login-view, so i used the stock django.contrib.auth.views.login-view by adding the line of
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html',}, name='login'),
to my urls.py and within the login.html-templates form-element:
{% if not next or not next.strip %}
{# avoid django.contrib.auth.views.login s default of /account/profile/ #}
{% url 'afterlogindefaultview' as next %}
{% endif %}
<input type="hidden" name="next" value="{{ next }}" />
which to my understanding follows the decoupling-practice of the url-configurations from the views.
so for views that should redirect to my apps login and afterwards head to a non-default view
i use
return HttpResponseRedirect('%s?next=%s' % (reverse('login'), reverse('mycustomnext')) )
from the view where i want to have the user to log in. i use this to get back to the view where i left off for logging the user in.
You can use a static redirect to /loggedin/ and then associate the url to a view that makes the correct redirect.
Login takes an extra step but if you want to use django's view it does the job.
create your own view for logging in, with it's own url, don't use the admin's one.
you can store the next page in the session, or pass it as a GET parameter to the login view
(i.e. /login?next=gallery) just don't forget to sanitize and validate that value before redirecting to it.

Categories