Python Django from does not work after refactoring - python

I have been working through the Tango With Django tutorial. However, I noticed that some of the examples did not adhere to what people consider Django best practices, so I went back to do a little refactoring. Here is how I first wrote a template for a form that allows a user to add a web page to a category.
<!DOCTYPE html>
<html>
{% extends 'rango/base.html' %}
{% block title %}Add a Page{% endblock %}
{% block body_block %}
<h1>Add a Page</h1>
<form id="page_form" method="post" action="/rango/category/{{ category_name }}/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"></input>
</form>
{%endblock%}
</html>
I then refactored the template like so:
<!DOCTYPE html>
<html>
{% extends 'rango/base.html' %}
{% block title %}Add a Page{% endblock %}
{% block body_block %}
<h1>Add a Page</h1>
<form id="page_form" method="post" action="{% url 'add_page' category_name %}"></form>
{% 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"></input>
</form>
{%endblock%}
</html>
However, now when I click the submit button, nothing happens. Here is the url pattern that I use:
url(r'^category/(?P<category_name_url>\w+)/add_page/$', views.add_page, name='add_page')
Here is my view:
#login_required
def add_page(request, category_name_url):
category_name = remove_underscores(category_name_url)
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
page = form.save(commit=False)
try:
cat = Category.objects.get(name=category_name)
page.category = cat
except Category.DoesNotExist:
return render(request, 'rango/add_page.html', {})
page.views = 0
page.save()
return category(request, category_name_url)
else:
print form.errors
else:
form = PageForm()
return render(request, 'rango/add_page.html',
{'category_name_url': category_name_url,
'category_name': category_name,
'form': form})
UPDATE:
Here is the code in 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_url>\w+)/$', views.category, name='category'),
url(r'^category/(?P<category_name_url>\w+)/add_page/$', views.add_page, name='add_page'),
url(r'^register/$', views.register, name='register'),
url(r'^login/$', views.user_login, name='login'),
url(r'^restricted/$', views.restricted, name='restricted'),
url(r'^logout/$', views.user_logout, name='logout'),
)
UPDATE:
I print out the result of {% url 'add_page' category_name %} and got /rango/category/Ruby/add_page/, which is the correct result. Looks like the url tag is resolving to the correct path. Still not sure why it is not working.

OMG! I feel so lame! This line was the issue:
<form id="page_form" method="post" action="{% url 'add_page' category_name %}"></form>
The fields and submit button were not enclosed in the form! Ugh!

Related

How to render to template with dropdownbox in django?

I'm a beginner Django. And I got a problem with rendering to the template.
I have a model(models.py) which has the class "FuelInfo"; includes ForeignKey.
from django.db import models
class Traveler(models.Model):
traveler_name = models.CharField(max_length=10)
def __str__(self):
return self.traveler_name
class FuelInfo(models.Model):
name = models.ForeignKey(Traveler, on_delete=models.SET_NULL, null=True)
car = models.CharField(null=True, max_length=50)
efficiency = models.FloatField()
def __str__(self):
return str(self.name)
Also views.py is like :
from django.shortcuts import render, get_object_or_404
from .models import FuelInfo
def traveler_list(request):
travelers = FuelInfo.objects.all()
context = {'travelers':travelers}
return render(request, 'fuelcost/home.html', context)
def traveler_detail(request, pk):
traveler = get_object_or_404(FuelInfo, pk=pk)
return render(request, 'fuelcost/calfuel.html', {'traveler': traveler})
And urls.py is :
from django.urls import path
from . import views
app_name = 'fuelcost'
urlpatterns = [
path('', views.traveler_list, name='home'),
path('<int:pk>/', views.traveler_detail, name='calfuel'),
]
I want to make a dropdown that is render to template "calfuel.html" in home.html.
So I made a template("home.html") like :
{% extends "base_generic.html" %}
{% block content %}
<body>
{% if travelers %}
<form method="POST" action="{% url 'fuelcost:calfuel' pk=traveler.pk %}">
{% csrf_token %}
<select name="traveler">
{% for traveler in travelers %}
<option value="{{ traveler.id }}">{{ traveler.name }}</option>
{% endfor %}
</select>
<input type="submit" value="Select" />
</form>
{% else %}
<p>No travelers are available</p>
{% endif %}
</body>
{% endblock %}
But it doesn't works and i received error.
(My urlpattern is fuelcost/.)
Actually I can go into fuelcost/1 or fuelcost/2 that is views.traveler_detail named "calfuel". But I can't go into fuelcost/ that is views.traveler_list named "home".
I don't know what I have to do more. plz, tell me what is wrong with this.
{% block content %}
<body>
{% if travelers %}
{% for traveler in travelers %}
<form method="POST" action="{% url 'fuelcost:calfuel' pk=traveler.pk %}">
{% csrf_token %}
<select name="traveler">
<option value="{{ traveler.id }}">{{ traveler.name }}</option>
</select>
<input type="submit" value="Select" />
</form>
{% endfor %}
{% else %}
<p>No travelers are available</p>
{% endif %}
</body>
{% endblock %}
you have to keep the form inside loop so that it can get pk of traveler

How to fix NoReverseMatch 'user' is not a registered namespace

I'm setting up a website, and want to make a user login page. But I always get "NoReverseMatch at /users/login/ and 'user' is not a registered namespace" when I am on the login page.
url.py
from django.urls import path
from django.contrib.auth.views import LoginView
from . import views
app_name ='users'
urlpatterns = [
path('login/', LoginView.as_view(template_name='users/login.html'),
name='login'),
]
login.html
{% extends "learning_logs/base.html" %}
{% block content %}
{% if form.errors %}
<p.Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action="{% url 'user:login' %}
{% csrf_token %}
{{ form.as_p }}
<botton name="sumbit">log in</button>
<input type="hidden" name="next"
value="{% url 'learning_logs:index' %}
</form>
{% endblock content %}
and base.html that login extends from
<p>
Learning Log -
Topics -
{% if user.is_authenticated %}
Hello, {{ user.username }}.
{% else %}
log in
{% endif %}
</p>
{% block content %}{% endblock content %}
You named your app_name='users' and you're calling 'user' in the template. That's why you're getting that. Also you have an opened but not closed single quote on your template.

NoReverseMatch at /app/detail/3/

I got an error,
NoReverseMatch at /app/detail/3/
Reverse for 'detail' with arguments '('',)' not found. 1 pattern(s) tried: ['app/detail\\/(?P<pk>[0-9]+)\\/$'] .
I wrote in views.py
def top(request):
content = POST.objects.order_by('-created_at')[:5]
page = _get_page(blog_content, request.GET.get('page'))
return render(request, 'top.html',{'content':content,"page":page})
class DetailView(generic.DetailView):
model = POST
template_name = 'detail.html'
in top.html
<div>
{% for content in page %}
<h2>{{ content.title }}</h2>
<p>SHOW DETAIL</p>
{% endfor %}
</div>
in detail.html
<div>
<h2>Comment List</h2>
Comment
{% for comment in post.comment_set.all %} Name:{{ comment.name }}
<br> Text:{{ comment.text }}
<br>
Reply
<br> {% endfor %}
</div>
<div>
<h2>Comment Form</h2>
<form action="" method="POST">
{{ form.as_p }} {% csrf_token %}
<button type="submit">Send</button>
</form>
</div>
in urls.py
urlpatterns = [
path('top/', views.top, name='top'),
path('detail/<int:pk>/', views.DetailView.as_view(template_name='detail.html'), name='detail'),
path('comment/<int:pk>/',views.comment, name='comment'),
path('recomment/<int:pk>/', views.recomment, name='recomment'),
]
When I access top.html, web site is shown correctly , so it is ok. But when I put SHOW DETAIL links, this error happens. I really cannot understand why this error happens.

DeleteView doesn't delete and just refreshes the delete page

When I click on my delete project link it takes me to my delete page with a button to click which should delete the model data of the project and then take me to the profile page. However when I click the delete button, the page just refreshes and no data gets deleted?!
What am I doing wrong here? Any help would be much appreciated :-)
Views
class DeleteProject(UpdateView):
model = UserProject
template_name = 'howdidu/delete_project.html'
def get_object(self, queryset=None):
obj = super(DeleteProject, self).get_object()
if not obj.user == self.request.user:
raise Http404
return obj
def get_success_url(self):
project_username = self.request.user.username
#project_slug = self.object.slug
return reverse('user_profile', kwargs={'username':project_username})
delete_project.html template
{% extends 'howdidu/base.html' %}
{% load staticfiles %}
{% block title %}Delete project{% endblock %}
{% block body_block %}
<h1>Delete project</h1>
<form method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ userproject.title }}"?</p>
<input type="submit" value="Confirm" />
</form>
{% endblock %}
Urls
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^register_profile/$', views.register_profile, name='register_profile'),
url(r'^update_profile/$', views.update_profile, name='update_profile'),
url(r'^create_project/$', login_required(views.CreateProject.as_view()), name='create_project'),
url(r'^(?P<username>\w+)/(?P<slug>[-\w]+)/update_project/$', login_required(views.UpdateProject.as_view()), name='update_project'),
url(r'^(?P<username>\w+)/(?P<slug>[-\w]+)/delete_project/$', login_required(views.DeleteProject.as_view()), name='delete_project'),
url(r'^(?P<username>\w+)/$', views.profile_page, name='user_profile'),
url(r'^(?P<username>\w+)/(?P<slug>[-\w]+)/$', views.project_page, name='user_project'),
)
Project.html template which has the delete link on
{% extends 'howdidu/base.html' %}
{% load staticfiles %}
{% block title %}Project{% endblock %}
{% block body_block %}
{% if project %}
<h1>{{ project.title }}</h1>
<img src="{{ project.project_picture.url }}" width = "300" height = "300" />
<h3>{{ project.project_overview }}</h3>
{% if user.is_authenticated %}
{% if project_user.username == user.username %}
<p>Edit project</p>
<p>Delete project</p>
{% endif %}
{% endif %}
{% else %}
The specified project {{ project.title }} does not exist!
{% endif %}
{% endblock %}
You must use DeleteView not UpdateView.
See here.

Display form fields one at a time in template-django

I have set of questions and its answers stored in db.I have a form to get answer for each question.I need to display only one question at a time in template and validate that answer against the original answer stored in db.
For now am able to display one value.But what i need is to display a question in a page and validate if the answer is correct,move on to display next question from db and so on. How do I achieve this?
form.py
from django import forms
class details_form(forms.Form):
answer = forms.CharField(widget=forms.TextInput())
views.py
def display_question(request):
context = RequestContext(request)
if request.method == 'GET':
print "GET"
form_class = details_form()
que_data = details.objects.get(que_id=1)
else:
##POST request
return render_to_response('sample/display_question.html',{'form':form_class,'que_data':que_data},context)
template:
{% extends 'sample/base.html' %}
{% block title %} Question {% endblock %}
{% block body_block %}
<p><strong>Your question : </strong></p>
"{{ que_data.que }}"
<p><strong>Type your answer here :<strong></p>
<form id='details_form' method = 'post' action='/next'>
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<br></br>
<input type ="submit" name="submit" value="Submit"/>
</form>
{% endblock %}
Update:
views.py
def display_question(request,question_id):
context = RequestContext(request)
form_class = details_form()
try:
quesno_id = {'id':question_id}
que_data = details.objects.get(que_id=question_id)
except details.DoesNotExist:
pass
if request.method == 'POST':
form = details_form(request.POST)
if form.is_valid():
user_answer = form.cleaned_data['answer']
if que_data.original_answer == user_answer:
return HttpResponseRedirect("question/%s/" %question_id+1)
else:
print form.errors
else:
pass
return render_to_response('sample/display_question.html',{'form':form_class,'que_data':que_data,'quesno_id':quesno_id},context)
template
{% extends 'sample/base.html' %}
{% block title %} Question {% endblock %}
{% block body_block %}
<p><strong>Your question {{ quesno_id.id}} : </strong></p>
"{{ que_data.que }}"
<p><strong>Type your answer here :<strong></p>
<form id='details_form' method = 'post' action="/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<br></br>
<input type ="submit" name="submit" value="Submit"/>
</form>
{% endblock %}
urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^question/(?P<question_id>\w+)/$',views.display_question,name='display_question'),
)
models.py
from django.db import models
class Songdata(models.Model):
que_id = models.AutoField(primary_key=True)
que = models.CharField(max_length=256)
original_answer = models.TextField()
def __unicode__(self):
return self.song_name
form.py
from django import forms
class details_form(forms.Form):
user_answer = forms.CharField(widget=forms.TextInput())
You need to use an absolute URL path like HttpResponseRedirect("/question/%s/" % (question_id+1)) (notice the leading slash)

Categories