Page not found (404) when submitting a form in Django - python

I am working through the Tango With Django tutorial. I am trying to allow the user to register with the app. However, when the user presses the submit button, I get this error message:
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/rango/register/rango/register/
Using the URLconf defined in tango_with_django_project.urls, Django tried these URL patterns, in this order:
^admin/
^rango/ ^$ [name='index']
^rango/ ^about$ [name='about']
^rango/ ^add_category/$ [name='add_category']
^rango/ ^category/(?P<category_name_url>\w+)/$ [name='category']
^rango/ ^category/(?P<category_name_url>\w+)/add_page/$ [name='add_page']
^rango/ ^register/$ [name='register']
media/(?P<path>.*)
The current URL, rango/register/rango/register/, didn't match any of these.
I'm not sure how that weird path is being built. Here is registration template:
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Register with Rango</h1>
{% if registered %}
Rango says: <strong>thank you for registering!</strong>
Return to the homepage.<br />
{% else %}
Rango says: <strong>register here!</strong><br />
<form id="user_form" method="post" action="rango/register/"
enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Register" />
</form>
{% endif %}
</body>
</html>
In order to get to the registration template, you need to click this link in the index template:
Register Here
Here is the register function in rango/views.py:
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
registered = True
else:
print user_form.errors, profile_form.errors
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request,
'rango/register.html',
{'user_form': user_form, 'profile_form': profile_form, 'registered': registered})
I am sure I am missing something small!

Currently you browser adds "rango/register/" to the end of the current URL.
If you changed it to "./" or "/rango/register/" it would point to itself, however these are not best practise.
For best practise use {% url "register" %} instead, that way it will automatically change is you change your url.py
e.g:
<form id="user_form" method="post" action="{% url "register" %}"
enctype="multipart/form-data">

Most likely the <form action> attribute is wrong.
Now it points relatively to:
rango/register/rango/register/
<form id="user_form" method="post" action="rango/register/" <--- relative
For a quick workaround try (not a best practice):
<form id="user_form" method="post" action="/rango/register/"
instead.
Learn how relative URL works within HTML pages and this should unravel the mystery.

It seems like the issue is with your URLs.py page - it seems like you haven't setup the url rewriting section of django

Related

Django form is not saving when I have action = to desired url

If I use action="" in my django form, the form works properly but sends the user to the wrong page. I want the user to go back to the macro/ page upon form submission, but when I add that url to action (like action="{% url 'macro' %}", it goes to the page but the form doesn't save. Any suggestion on how to handle this? Code below:
(Option 1) macro_update.html -> the form here works properly, but takes the user to the wrong page
<ul>
<form action="" method="post">
{% csrf_token %}
{{ macro_form.as_ul }}
<input type="submit" value="Submit">
</form>
</ul>
(Option 2) macro_update.html -> the user is redirected to the right page upon submission, but the form data doesn't update/save
<ul>
<form action="{% url 'macro' %}" method="post">
{% csrf_token %}
{{ macro_form.as_ul }}
<input type="submit" value="Submit">
</form>
</ul>
views.py
#login_required(login_url='login')
def macroUpdate(request):
if request.method == "POST":
macro_form = MacroForm(request.POST, instance=request.user.profile)
if macro_form.is_valid():
macro_form.save()
messages.success(request,('Your macros were successfully updated!'))
else:
messages.error(request,('Unable to complete request'))
return redirect("profile")
macro_form = MacroForm(instance=request.user.profile)
context = {"user":request.user, "macro_form":macro_form }
return render(request, 'macro_update.html', context)
urls.py
urlpatterns = [
path('', views.loginPage, name='login'),
path('register/', views.registerPage, name='register'),
path('profile/', views.profilePage, name='profile'),
path('profile/update/', views.profileUpdate, name='profile-update'),
path('logout/', views.logoutUser, name='logout-user'),
path('macro/', views.macroPage, name='macro'),
path('macro/update/', views.macroUpdate, name='macro-update'),
]
I want the user to go back to the macro/ page upon form submission, but when I add that url to action (like action="{% url 'macro' %}", it goes to the page but the form doesn't save.
It is because form data must go to macroUpdate view to save not macroPage, to redirect on macro page after form submission you can use redirect("macro") so:
views.py:
#login_required(login_url='login')
def macroUpdate(request):
if request.method == "POST":
macro_form = MacroForm(request.POST, instance=request.user.profile)
if macro_form.is_valid():
macro_form.save()
messages.success(request,('Your macros were successfully updated!'))
else:
messages.error(request,('Unable to complete request'))
return redirect("macro")
macro_form = MacroForm(instance=request.user.profile)
context = {"user":request.user, "macro_form":macro_form }
return render(request, 'macro_update.html', context)
Just remove the action attribute in from tag of macro_update.html since Django always takes current page route so:
<ul>
<form method="POST">
{% csrf_token %}
{{ macro_form.as_ul }}
<input type="submit" value="Submit">
</form>
</ul>

Django Form submission leads to 404 Error

When an user submits a form, I am receiving the following error:
Page not found (404)
Request Method: csrfmiddlewaretoken=uaL0Ogej2bd0oSaNLXYwu1CxSPWz6mcs0PuXiwM2mpe01VecK5IVBK40xvqcFCJF&views=0&likes=0&slug=&name=do+do+ahadalfjkdas%3Bldfjksal%3B12321&submit=Create+CategoryPOST
Request URL: http://127.0.0.1:8000/rango/add_category/rango/add_category/
Using the URLconf defined in tango_with_django_project.urls, Django tried these URL patterns, in this order:
^$ [name='index']
^admin/
^rango/ ^$ [name='index']
^rango/ ^about/ [name='about']
^rango/ ^category/(?P<category_name_slug>[\w\-]+)/$ [name='show_category']
^rango/ ^page/(?P<page_name_slug>[\w\-]+)/$ [name='show_page']
^rango/ ^add_category/$ [name='add_category']
The current path, rango/add_category/rango/add_category/, didn't match any of these.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
It seems like I am appending rango/add_category twice and not re-referring back to the index page. But I am not sure what I am overlooking.
Here's the relevant template:
<!-- created in c7 for form viewing-->
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Category</h1>
<div>
<form id="category_form" method="post" action="rango/add_category/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{hidden}}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Create Category" />
</form>
</div>
</body>
</html>
And the relevant forms file:
#file added c7, forms
from django import forms
from rango.models import Page, Category
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128,
help_text="Please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
#Inline class to provide additional info on the form
class Meta:
#provide an association b/t ModelForm and model
model = Category
fields = ('name',)
The relevant urls file:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^about/', views.about, name='about'),
#?P makes group to match the slug
url(r'^category/(?P<category_name_slug>[\w\-]+)/$',
views.show_category, name='show_category'),
#page slug added at ex at end of 6
# not sure if needed, given index view ...
url(r'^page/(?P<page_name_slug>[\w\-]+)/$',
views.show_page, name='show_page'),
#show page added in ex at end of 6
#next added at c7 for forms
#ordering may matter for processing of requests -- see official docs
url(r'^add_category/$', views.add_category, name='add_category')]
The relevant view from views:
def add_category(request):
form = CategoryForm()
#HTTP Post? (that is, did user supply data?)
if request.method == 'POST':
form = CategoryForm(request.POST)
if form.is_valid():
form.save(commit=True)
# could also give confirmation message if you wanted
return index(request)
else:
print(form.errors)
return render(request, 'rango/add_category.html', {'form': form})
# new template created
Thanks in advance.
Try to change your action url of your form
<form id="category_form" method="post" action="{% url 'add_category' %}">
For more information please read https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#url

Not able to redirect to view after login

I am trying to create a redirect when the user logs in. For example when user tries to access a link to create blog post he is prompted to log in , and after he gets logged in he is redirected to the page to create the post. I am extracting the next parameter from the url.
blog.urls
from django.conf.urls import url
from blog import views
urlpatterns=[
url(r'^$',views.index,name="index"),
url(r'^signup/$',views.signup_view,name="signup_view"),
url(r'^login/$',views.login_view,name="login_view"),
url(r'^create-post/$',views.create_blog,name="create_post"),
url(r'^logout/$',views.logout_view,name="logout_view"),
]
blog.views:
def login_view(request):
if request.method == 'POST':
form=LoginForm(request.POST)
if form.is_valid():
username=form.cleaned_data['username']
password=form.cleaned_data['password']
user=authenticate(username=username,password=password)
if user is not None:
if user.is_active:
login(request,user)
go_to=request.GET.get('next','/')
print go_to
return HttpResponseRedirect(go_to)
else:
return HttpResponse("Not active")
else:
return HttpResponse("User doesn't exist")
else:
form=LoginForm()
return render(request,'blog/login.html',{'form':form})
and blog/login.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form method="POST" action="/login/">
{% csrf_token %}
<table>
{{form.as_table}}
</table>
<button type="submit">Submit</button>
</form>
</body>
</html>
Whenever I login it shows the next parameter as '/' while there is "next=/create-blog/" in the url. Please suggest any solution.
you need:
action="/login/{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}"
If the value of {{ request.GET.next }} includes parameters, e.g. http://example.com/?var1=abc&var2=def, then use URL encoding {{ request.GET.net | urlencode }}.

Django - using generic login view not working

EDIT: the view now does log me in when I enter a correct username and password, but doesn't return any errors when I enter incorrect username and passwords.
I am using the generic login view provided by Django. This is my login.html template:
<body>
<h1>User Login</h1>
{% if form.has_errors %}
<p>Your username and password did not match.
Please try again.</p>
{% else %}
<form method="post" action=" . ">{% csrf_token %}
<p><label for="id_username">Username:</label>
{{ form.username }}</p>
<p><label for="id_password">Password:</label>
{{ form.password }}</p>
<input type="hidden" name="next" value="/" />
<input type="submit" value="login" />
</form>
{% endif %}
</body>
Now, I am following the tutorial in the book called "Pact Publishing. Learning Website Development with Django". The view never returns
form.has_errors
even though I purposely submit an incorrect username and password. It just keeps returning me to the same page after I click submit. Also, according to the HTML book I read, it said that the 'action' attribute in the form is the URL of the page on the server that will retrieve the information. Is that why it isn't working? Because my
action=" . "
?
EDIT: the view is the generic login view:
#sensitive_post_parameters()
#csrf_protect
#never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
request.session.set_test_cookie()
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
and my urls.py is just
url(r'^$', main_page),
url(r'^user/(\w+)/$', user_page),
url(r'^login/$', login),
Ah, found the answer over here:
form.has_errors tag not working
form.has_errors
was replaced with
form.errors
Try this.
Login.Html
<form action ="." method = POST>
{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "login" class="btn">
</form>
urls.py
from django.contrib.auth.views import login, logout
from django.conf.urls import *
urlpatterns = patterns('',
url(r'login/',login,kwargs = {'template_name' : 'templates/auth/login.html'},
url(r'logout', logout,kwargs = {'template_name' : 'templates/auth/logout.html'}),
)
settings.py
LOGIN_REDIRECT_URL = '/dashboard'
LOGIN_URL = '/login/'

Unable to update CharField - Django

First of all I'm glad to be here, I read you lately and i found useful answers here.
This is my first post so please be kind with me, I'm a newbie in programming.
So, I'm writing my 1st web application in Django - a todo app and I don't know how to write the function that does this this. I found something in Django docs and in other related discussions but it doesn't work.
Here's my code:
#models.py
class Task(models.Model):
user = models.ForeignKey(User)
task = models.CharField(max_length=200)
initialized_at = models.DateTimeField(auto_now_add=True)
due_date = models.DateField(default=datetime.now)
done = models.BooleanField(default=False)
def __unicode__(self):
return self.task
#views.py
def edit_task(request, id):
if request.method == 'POST':
task_to_edit = Task.objects.get(pk=task_id)
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm()
return render(request, 'todo/edit_task.html', {'form': form})
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
#edit_task.html
{% block content %}
<form action="/edit_task/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
When I submit the updated form I get this error:
Page not found (404)
Request Method: POST
Request URL: hxxp://127.0.0.1:8000/edit_task/
Using the URLconf defined in jbz.urls, Django tried these URL patterns, in this order:
^admin/
^$ [name='index']
^(?P<task_id>\d+)/$
^(?P<task_id>\d+)/$
^add-task/$
^delete-task/(?P<task_id>\w+)/$
^edit_task/(?P<id>\w+)/$
^done/(?P<task_id>\d*)/$
The current URL, edit_task/, didn't match any of these.
and the root urls.py looks like:
url(r'', include('todo.urls'))
#edit_task.html
{% block content %}
<form action="/edit_task/{{task.id}}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
Notice how I added {{task.id}} expression in <form action="/edit_task/{{task.id}}" method="post">
IMPORTANT NOTE: Substitute {{task.id}} to whatever variable accomplishes this in your template.
The reason why you get the error is because edit_task/ is not getting the other part, task_id to match the regular expression:
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
UPDATE: Also your edit_task view has potential errors as well>
def edit_task(request, id):
task_to_edit = Task.objects.get(pk=id)
if request.method == 'POST':
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm(instance=task_to_edit)
# you don't pass any task variable to the view so the form view
# won't know which task to edit, you'll have to handle that
return render(request, 'todo/edit_task.html', {'form': form, 'task':task_to_edit})
Note: I corrected the code in the view a little. Now the task_to_edit is passed also to the Form to fill the fields when the view is requested via GET. Notice that in order to access to this view, the url in the browser should look like this http://www.example.com/edit_task/2
If other wise you try to access http://www.example.com/edit_task without passing the id you'll get Error 404.
Hope this helps!
I think your pattern for edit task expects an id - task name. Try changing your URL pattern:
'^edit_task/(?P<task_id>\w+)/$'
to
'^edit_task/$'
or providing the task id that you want to edit.
Just add name space to your url and according update your template.
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task', name= "edit_task")
#edit_task.html
{% block content %}
<form action="{% url 'edit_task' task_id %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}

Categories

Resources