Django Form submission leads to 404 Error - python

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

Related

Allow user to edit profile information and submit it causing page to redirect to profile page.

In django I am attempting to allow that user to edit his/her profile information, press submit, and have the the change reflect in his/her profile page.
This is the code :
In the views.py document in my application
User is allowed to view the profile page
def view_profile(request):
var = { 'user' : request.user }
return render(request, 'accounts/profile.html', var)
User is allowed to edit the profile page
def edit_profile(request):
if request.method == 'POST':
form = UserChangeForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('account/profile')
else:
form = UserChangeForm(instance=request.user)
var = {'form' : form }
return render(request, 'accounts/edit_profile.html', var)
This is the urls.py document
Import modules
from django.conf.urls import url
from . import views
Defined the urls
urlpatterns = [
url(r'^profile/$', views.view_profile, name = 'view_profile'),
url(r'^profile/edit/$', views.edit_profile, name = 'edit_profile')
]
This is the edit_profile
{% extends 'base.html' %}
{% block head %}
<title>{{ user }}</title>
{% endblock %}
{% block body %}
<div class = "container">
<form method = "post">
{% csrf_token %}
{{ form.as_p }}
<button class = "btn btn-default" type="submit">Submit</button>
</form>
</div>
{% endblock %}
When I edit user model on the edit_profile.html page and submit, it redirects
from :
http://127.0.0.1:8000/account/profile/edit/
To :
http://127.0.0.1:8000/account/profile/edit/account/profile
This latter urls is not accurate, it should redirect
To :
http://127.0.0.1:8000/account/profile
This is how that page looks
When you redirect you should include a leading slash to make it an absolute url:
return redirect('/account/profile')
You can avoid hardcoding the url by using the URL pattern name instead. The redirect shortcut will reverse the url for you:
return redirect('view_profile')

How to store data from html form to postgres database using Django 1.10?

I am new to Django , i just created a simple form to store the user input to database, but the data is not stored while clicking submit button, when i click the submit button the current page is refreshed, but data not stored in database. what is wrong in my code ?.I have created the following models, and my code is ,
mysite/jobs/models.py
from django.db import models
class Cost(models.Model):
cost = models.FloatField()
date = models.DateField()
mysite/jobs/views.py
from django.shortcuts import render
from jobs.forms import CostForm
from jobs.models import Cost
def costView(request):
if request.method == 'POST':
form = CostForm(request.POST)
if form.is_valid():
date = request.POST.get('date','')
cost = request.POST.get('cost','')
cost_obj = Cost(date=date, cost=cost)
cost_obj.save()
return HttpResponse("csdfsdf")
else:
form = CostForm()
return render(request,'jobs/cost.html',{'form':form,})
mysite/jobs/forms.py
from django import forms
class CostForm(forms.Form):
date = forms.DateField()
cost = forms.FloatField()
mysite/jobs/templates/jobs/cost.html
<form action="{% url 'jobs:cost' %}" method="post"> {% csrf_token %}
<p><label for="date">Date:</label><input type="text" name="date" value={% now "Y-m-d" %}/></p>
<p><label for="cost">Cost:</label><input type="text" name="cost" value="0" id="cost"/></p>
<input type="submit" value="Submit"/>
</form>
mysite/jobs/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.costView, name='cost'),
]
mysite/urls.py
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^', include('jobs.urls',namespace="jobs")),
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
Your form is presumably not valid.
You should use {{ form.errors }} in the template to display the validation errors. Also, you should use {{ form.date }} and {{ form.cost }} to display the fields, rather than creating input tags manually, so that the values are re-populated when validation fails.
Since you made mysite/jobs/forms.py, you can use that in your HTML template:
<form action="{% url 'jobs:cost' %}" method="post"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
The reason why your form wasn't saving is probably because of your mysite/jobs/views.py. Since you don't need to add additional data besides the date and cost in the form, you can go ahead and save it instead of creating cost_obj:
if request.method == 'POST':
form = CostForm(request.POST)
if form.is_valid():
form.save()
If you do want to create cost_obj, do it this way:
cost_obj = form.save(commit=False)
You can then add additional information into the object before saving it. e.g.:
cost_obj.user = request.user
cost_obj.save()

Tango with Django - Chapter 8 - Exercise

I need some help getting the add_page function to work properly. I am very new to HTML and even newer to Django. The chapter I am working on can be found here: http://www.tangowithdjango.com/book17/chapters/forms.html. Currently my relevent files look like this:
Forms.py
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)
# An inline class to provide additional information on the form.
class Meta:
# Provide an association between the ModelForm and a model
model = Category
fields = ('name',)
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
# Provide an association between the ModelForm and a model
model = Page
# What fields do we want to include in our form?
# This way we don't need every field in the model present.
# Some fields may allow NULL values, so we may not want to include them...
# Here, we are hiding the foreign key.
# we can either exclude the category field from the form,
exclude = ('category',)
#or specify the fields to include (i.e. not include the category field)
#fields = ('title', 'url', 'views')
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
# If url is not empty and doesn't start with 'http://', prepend 'http://'.
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
Views.py:
from django.shortcuts import render
from django.http import HttpResponse
from rango.models import Category, Page
from rango.forms import CategoryForm, PageForm
def index(request):
# Query the database for a list of ALL categories currently stored.
# Order the categories by no. likes in descending order.
# Retrieve the top 5 only - or all if less than 5.
# Place the list in our context_dict dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-view')[:5]
context_dict = {'categories': category_list,
'pages': page_list}
# Render the response and send it back!
return render(request, 'rango/index.html', context_dict)
def category(request, category_name_slug):
# Create a context dictionary which we can pass to the template rendering engine.
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
context_dict['category_name_slug'] = category_name_slug
# Retrieve all of the associated pages.
# Note that filter returns >= 1 model instance.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displays the "no category" message for us.
pass
# Go render the response and return it to the client.
print context_dict
return render(request, 'rango/category.html', context_dict)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# Save the new category to the database.
form.save(commit=True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print form.errors
else:
# If the request was not a POST, display the form to enter details.
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'rango/add_category.html', {'form': form})
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
# probably better to use a redirect here.
return category(request, category_name_slug)
else:
print form.errors
else:
form = PageForm()
context_dict = {'form':form, 'category': cat}
return render(request, 'rango/add_page.html', context_dict)
urls.py
from django.conf.urls import patterns, url
from rango import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
# url(r'^about/$', views.about, name='about'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$', views.add_page, name='add_page'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),)
I think this ^ is where I am encountering the issue. I manage to get to the "add a page" screen, but when I try to submit something, I receive an error that states I am only supplying 1 argument and add_page() requires 2. I think I may need an additional url that is similar to the "add_category" URL, but that must mean by other URL is pointing to the wrong place?
category.html
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>{{ category_name }}</h1>
{% if category %}
{% if pages %}
<ul>
{% for page in pages %}
<li>{{ page.title }}</li>
{% endfor %}
</ul>
{% else %}
<strong>No pages currently in category.</strong>
{% endif %}
<li>Add a New Page</li>
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
</body>
</html>
add_page.html:
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/add_page/">
{% 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 Page" />
</form>
</body>
</html>
I edited the add_page function to include category_name_slug:
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
# probably better to use a redirect here.
return category(request, category_name_slug)
else:
print form.errors
else:
form = PageForm()
# made the change here
context_dict = {'form':form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
Then I edited the add_page.html to look like this:
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/category/{{ category_name_slug }}/add_page/">
{% 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 Page" />
</form>
</body>
</html>
if you dont wanna edit your views.py
just doit
<!DOCTYPE html>
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/category/{{ category }}/add_page/">
{% 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 Page" />
</form>
</body>
</html>
but i have problem to it still cannot be save on database.

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

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

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