Django: get a NoReverseMatch while rendering error - python

I seem to be getting a Caught NoReverseMatch error. I am not so sure what is causing the problem. Have a look at the full error.
Caught NoReverseMatch while rendering: Reverse for 'mmc.views.edit_note' with arguments '(1L, '')' and keyword arguments '{}' not found.
On my get_client page. I have a link to the edit note page. I am assuming the problem might be here in my template. I think the note.pk is the problem.
Edit Note
Here is also some more information which could help.
urls.py
(r'^clients/(?P<client_id>\d+)/$', views.get_client),
(r'^clients/notes/(?P<client_id>\d+)(?P<note_id>\d+)$', views.edit_notes),
views.py
#login_required
def edit_notes(request, client_id = 0, note_id = 0):
client = None
note = None
try:
client = models.Client.objects.get(pk = client_id)
note = models.Note.objects.get(pk = note_id)
except:
return HttpResponseNotFound()
if request.method == 'POST':
form = forms.NoteForm(request.POST, instance=note)
if form.is_valid():
note = form.save(commit=False)
note.user = request.user
note.client = client
note.save(True)
request.user.message_set.create(message = "Note is successfully added.")
return HttpResponse("<script language=\"javascript\" type=\"text/javascript\">window.opener.location = window.opener.location; window.close();</script>")
else:
form = forms.NoteForm(instance=note)
return render_to_response('note_form.html', {'form':form, 'client':client, 'note':note}, context_instance = RequestContext(request))
*EDIT: * Seem to have corrected most of it Here are some changes I have made.
Template
{% for note in notes %}
Edit Note
{% endfor%}
urls.py
(r'^clients/notes/(?P<client_id>\d+)/(?P<note_id>\d+)/$', views.edit_note)
Now the only problem is it displays all of the links to each edit form notes for an individual client. I only want the link for the latest note and only the latest note. Is there a possible way?

The client.pk and note.pk are empty values, so they don't match the regex.

(r'^clients/(?P<client_id>\d+)/$', views.get_client) should be something like url(r'^clients/(?P<client_id>\d+)/$', views.get_client, name='MY_URL_NAME') then called with {% url MY_URL_NAME client.pk %}
and import url from django.conf.urls.defaults

Related

Changing value type doesn't change ValueError invalid literal for int() with base 10: ''

I'm very new to Python and am building a basic blog in django. I am trying to enable editing of individual blog posts. I have to 'get' these individual blog posts so I can edit them. So far, the system isn't liking my '.get' method and shows me a ValueError. I have tried changing the value type to int, str, float, even complex. It all either returns the same or says it doesn't like 'id' or even 'pk' if I change it to that.
Here is the code.
views.py
from django.shortcuts import render
from blogs.models import BlogPost
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .forms import PostForm
def index(request):
"""The home page for blogs"""
blogposts = BlogPost.objects.order_by('date_added')
context = {'blogposts': blogposts}
return render(request, 'blogs/index.html', context)
def blogpost(request, blogpost_id):
"""Show a single post"""
postings = BlogPost.objects.get(id=blogpost_id)
context = {'postings': postings}
return render(request, 'blogs/blogpost.html', context)
def new_post(request):
"""Writ a new post to the blog"""
if request.method != 'POST':
# No data submitted; create a blank form.
form = PostForm()
else:
# POST data submitted; process data
form = PostForm(data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('blogs:index'))
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_entry(request, entry_id):
"""Edit an existing entry"""
entry = BlogPost.objects.get(id=entry_id)
if request.method != 'POST':
# Initial request; pre-fill form with the current entry
form = PostForm(instance=entry)
else:
# POST data submitted; process data
form = PostForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('blogs:blogpost', args[entry_id]))
context = {'entry': entry, 'form': form}
return render(request, 'blogs/edit_entry.html', context)
If you'll notice, under def blogpost(request, blogpost_id):, I was able to employ the .get method in the same exact way and it was successful. What's more, the .get should work as an int anyway since the link is a whole number.
models.py
from django.db import models
class BlogPost(models.Model):
"""A blog post"""
title = models.CharField(max_length=200)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a string rep of model"""
return (str(self.title + " : " + self.text))
urls.py
"""URL Configs for app blogs"""
from django.conf.urls import url
from blogs import views
urlpatterns = [
#Home page
url(r'^$', views.index, name='index'),
#Individual Postings Pages
url(r'^(?P<blogpost_id>\d+)/$', views.blogpost, name='blogpost'),
#New Post Page
url(r'^new_post$', views.new_post, name='new_post'),
#Page for editing a post
url(r'^edit_entry/(?P<entry_id>)/$', views.edit_entry, name='edit_entry'),
]
For the
(?P<entry_id>)/$', I did take out the portion,\d+ , because the system read the '\' back as '\\' so I took it out.
forms.py
from django import forms
from .models import BlogPost
class PostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['text']
labels = {'text':''}
widgets = {'text': forms.Textarea(attrs={'cols':80})}
What can I do to isolate and get the specific posts to edit them?
Thanks to anyone who answers this, in advance.
========================================================================
#Alasdair
I did add \d+ to the url and this is what I received...
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/edit_entry//
Using the URLconf defined in blog.urls, Django tried these URL patterns, in this order:
^admin/
^ ^$ [name='index']
^ ^(?P<blogpost_id>\d+)/$ [name='blogpost']
^ ^new_post$ [name='new_post']
^ ^edit_entry/(?P<entry_id>\d+)/$ [name='edit_entry']
The current URL, edit_entry//, 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.
Also, when I do that, it changes the behavior of the individual blog post. I get this response of the detailed view of the original post:
Exception Type: NoReverseMatch
Reverse for 'edit_entry' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['edit_entry/(?P<entry_id>\\d+)/$']
{% block content %}
<p>This is supposed to be for one post</p>
<p>{{ postings }}</p>
<p>Edit entry:</p>
edit entry
{% endblock content %}
The exception message you get is because you are trying to parse the empty string as an integer int(""). That operation makes no sense. The id pattern in the url should be at least one character.
(?P<entry_id>) is a completely useless pattern, since it contains no characters. It will always match an empty string '' and pass that to your view function.
(?P<entry_id>)/$, I did take out the portion,\d+ , because the system read the \ back as \\ so I took it out.
That's how it's supposed to work. There's no reason to take anything out.

I want something to be executed through django

I know this question was asked before, but none worked for me. I have this code that I want it to be executed when a button is clicked and a message is passed
import time
from sinchsms import SinchSMS
number = '+yourmobilenumber'
message = 'I love SMS!'
client = SinchSMS(your_app_key, your_app_secret)
print("Sending '%s' to %s" % (message, number))
response = client.send_message(number, message)
message_id = response['messageId']
response = client.check_status(message_id)
while response['status'] != 'Successful':
print(response['status'])
time.sleep(1)
response = client.check_status(message_id)
print(response['status'])
Basically, what I need is to add an input in a template "HTML File", this input get passed to the message variable in the code above, same with the number. I can easily do that with instances, but how can the below get executed when a button is clicked from the form in the template?
I'm kinda newbie in Django and still finding my way
Here is the tutorial that explains how to make the python file, but execute it from the shell, not a django application.
I hope I was clear describing my problem and any help would be appreciated!
All you need is a form with a message field. In a view, you want to show that form and when the user press submit, you want to execute your script.
Here is some pseudo-code:
urls.py
url('^my-page/' my_views.my_view, name='my-page'),
forms.py
SmsForm(forms.Form):
message = fields.CharField(...)
my_views.py
def my_view(request):
form = SmsForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
send_sms(form.cleaned_data['message']) # do this last
messages.success(request, "Success")
return HttpResponseRedirect(request.path)
else:
messages.warning(request, "Failure")
return render(request, 'my_template.html', {'form': form})
Check the Django documentation about urls, views, forms and messages and proceed step by step:
get the page to load
get the form to load
get the form submission to work and simply show "Success" or "Failure"
finally, write the send_sms function (you've almost done it)
Lets start from the dust cloud.
What you are asking is mostly about how the web pages work. You need to know how to pass parameters using HTML. There are lots of ways to do it. But with django there is a pattern.
You need a url, and a view to catch any requests. Then you need to create a template and a form inside it. With this form you could create some requests to send data to your view.
To create you need to edit urls.py inside your project add an url:
urls.py
from django.conf.urls import url
from my_app.views import my_view
urlpatterns = [
...
url(r'^my_url$', my_view, name='my_view')
...
]
For more about urls please look at URL dispatcher page at documentation.
Then create your view inside your app which is my_app in my example. Edit my_app/views.py
my_app/views.py
from django.http import HttpResponse
def my_view(request):
return HttpResponse('IT WORKS!')
This way you get a working view which could be accessed with path /my_url. If you run ./manage.py runserver you could access your view from http://localhost:8000/my_url.
To create a form you need to create a template. By default django searches app directories for templates. Create a templates directory in your app, in our case my_app/templates and create an HTML file inside. For example my_app/templates/my_form.html. But i advice to create one more directory inside templates directory. my_app/templates/my_app/my_form.html. This will prevent template conflicts. You can check Templates page at documentation for more.
my_app/templates/my_app/my_form.html
<html>
<body>
<form action="/my_url" method="POST">
{% csrf_token %}
<input type="text" name="number">
<input type="text" name="message">
<input type="submit" value="Run My Code">
</form>
</body>
</html>
This is the one of the ways of creating your form. But I do not recommend it. I will make it prettier. But first lets "Make it work", edit your views.py:
csrf_token is a django builtin template tag, to put CSRF token into your form. By default django requires CSRF tokens at every post
request.
my_app/views.py
from django.http import HttpResponse
from django.shortcuts import render
def my_view(request):
if request.method == 'GET':
return render('my_app/my_form.html')
elif request.method == 'POST':
# get post parameters or None as default value
number = request.POST.get('number', None)
message = request.POST.get('message', None)
# check if parameters are None or not
if number is None or message is None:
return HttpResponse('Number and Message should be passed')
# your code goes here
...
return HttpResponse('Your code result')
Till this point the purpose of this answer was "Making it work". Lets convert it nice and clean. First of all we would create Form. Forms are like models, which helps you create forms as objects. It also handles form validations. Forms are saved inside forms directory generally. Create my_app/forms.py and edit it:
my_app/forms.py
from django import forms
class MyForm(forms.Form):
number = forms.CharField(max_length=15, required=True)
message = forms.CharField(max_length=160, required=True)
Put your form inside your template:
my_app/templates/my_app/my_form.html
<html>
<body>
<form action="{% url 'my_view' %}" method="POST">
{% csrf_token %}
{{ form }}
</form>
</body>
</html>
Besides the form, the action of the HTML form tag is also changed.
url template tag is used to get url form url name specified in urls.py.
Instead of url tag, {{ request.path }} could have been used.
Create a form instance and pass it to the template rendering:
my_app/views.py
from django.http import HttpResponse
from django.shortcuts import render
from .forms import MyForm
def my_view(request):
if request.method == 'GET':
form = MyForm()
return render('my_app/my_form.html', {'form': form})
elif request.method == 'POST':
form = MyForm(request.POST)
# check if for is not valid
if not form.is_valid():
# return same template with the form
# form will show errors on it.
return render('my_app/my_form.html', {'form': form})
# your code goes here
...
return HttpResponse('Your code result')
You can use class based vies to write your view, but it's not necessary. I hope it helps.
You can create a view that takes up query parameters from the url and use it for further implementation. Then you can create a link/button in the html template which can redirect you to that url. For example:
in urls.py:
url(r'^run_a/(?P<msg>\w{0,25})/(?P<num>\w{0,25})/$', yourcode, name='get_msg'),
in template:
submit
in views.py:
def get_msg(request,msg,num):
message=msg
number=num
#rest of the code
Hope this helps :)

forms in django, overriding validation on file upload to make sure just one value is there

Edit: Mostly got this working with a clean update
I added docfile2 and docfile3 beyond the example I used to code this. I also changed the view to handle them:
#login_required(login_url='/ngasite/login/')
def list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
for fieldname in ('docfile', 'docfile2', 'docfile3'):
file = form.cleaned_data[fieldname]
if file:
Document(docfile=file).save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('ngasite:list', args=""))
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
paginator = Paginator(documents, 25)
page = request.GET.get('page')
try:
docs = paginator.page(page)
except PageNotAnInteger:
docs = paginator.page(1)
except EmptyPage:
docs = paginator.page(paginator.num_pages)
# Render list page with the documents and the form
return render_to_response(
'ngasite/list.html',
{'documents': documents, 'form': form, 'docs':docs},
context_instance=RequestContext(request)
)
This worked pretty well, I can
handle three files on my form now instead of one. But relisting after a post gives me an attribute has no file associated with it error. I am guessing because my checks for saving in the view is not really working correctly and saving regardless if there was a file or not. Maybe my python syntax is bad?
no errors int he console though.
This is what is failing in my list.html template:
{% if docs %}
<ul>
{% for doc in docs %}
<li>{{ doc.docfile.name }} </li>
{% endfor %}
</ul>
{% else %}
<p>No documents.</p>
{% endif %}
So my real forms.py with the overriding of the is_valid
from django import forms
class DocumentForm(forms.Form):
docfile = forms.FileField(
label='Select a file',
help_text='max. 7 Gigabytes',
required=False
)
docfile2 = forms.FileField(
label='Select a file',
help_text='max. 7 Gigabytes',
required=False
)
docfile3 = forms.FileField(
label='Select a file',
help_text='max. 7 Gigabytes',
required=False
)
def clean(self):
data = super(DocumentForm, self).clean()
if not (data['docfile'] or data['docfile2'] or data['docfile3']):
return ValidationError('You must upload at least one file.')
return data
What am i missing? my view fails on lines like
docfile=request.FILES['docfile'] cause it knows its missing, I thought my if newdoc2: etc would handle that but it doesnt work like I think it does/should
Ultimately as I learn more python and Django i want to turn this into a nice file uploader with responses to the browser to show the upload progress etc.
You should set your fields to required=False, which will avoid a validation error if any field is empty:
docfile3 = forms.FileField(
label='Select a file',
help_text='max. 7 Gigabytes',
required=False
)
Then in your form clean method check to see if at least one file is there:
from django.core.exceptions import ValidationError
def clean(self):
data = super(DocumentForm, self).clean()
# if there are already form errors, don't proceed with additional
# validation because it may depend on fields which didn't validate.
if self.errors:
return data
if not (data['docfile1'] or data['docfile2'] or data['docfile3']):
return ValidationError('You must upload at least one file.')
return data
I have not actually run this code so there may be some little issue but you get the idea...
In your view form_valid() method, there are problems with your saving code. Do something more like this:
for fieldname in ('docfile', 'docfile2', 'docfile3'):
file = form.cleaned_data.get(fieldname, None)
if file:
Document(docfile = file).save()

Django - In one view, how do I "return render/Httpresponse/etc" to another view?

So say I have a view called addPost(like a wall post). It's a model form page for a post object. There are two cases, either the request.method is post, or it isn't. In the case that it's a POST method, I want to return to the profile page after the post is submitted.
I've had this problem a few times, and it usually comes in the form of NoReverseMatch Errors.
How do you "return render/Httpresponse/etc" to another view? in Django? I feel like any solutions I've had before have been really hackish and I want to proper way to implement this sort of feature.
I do want to note that I get this error on myapp/profile.html
Here is the trackback I have:
NoReverseMatch at /myapp/profile/1/
Reverse for 'addpost' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Request Method: GET
Request URL: http://127.0.0.1:8000/myapp/profile/1/
Django Version: 1.8.2
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'addpost' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Exception Location: /Library/Python/2.7/site-packages/django/core/urlresolvers.py in _reverse_with_prefix, line 496
Python Executable: /Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
Python Version: 2.7.8
Python Path:
['/Users/me/project',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/setuptools-18.0.1-py2.7.egg',
'/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
'/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages',
'/Library/Python/2.7/site-packages']
Server time: Tue, 14 Jul 2015 08:12:13 +0000
It occurs at this line of code in the html, the button that links to the add_post view.
profile.html
{% if user == currUser %}
<a href="
{% url 'addpost' %}
" class = "btn btn-info"> <span class="glyphicon glyphicon-plus"></span></a>
{% endif %}
and it highlights this bit of code in Debug:
~/myapp/views.py in profile
return render_to_response('myapp/profile.html', {'currUser': currUser}, context) ...
▼ Local vars
Here are the two views, profile and add_post.
#login_required
def profile(request, id):
context = RequestContext(request)
currUser = User.objects.get(pk = id)
profile = UserProfile.objects.filter(user = currUser)
return render_to_response('myapp/profile.html', {'currUser': currUser}, context)
#login_required
#login_required
def add_post(request):
context = RequestContext(request)
if request.method == 'POST':
# #create a form instance and populate it with data from the request
form = PostForm(request.POST)
if form.is_valid():
#process data in form.clean_data
post = Post(user = request.user, title =form.cleaned_data['title'], body=form.cleaned_data['body'])
post.save()
return redirect(reverse('myapp/profile', args=[request.user.pk]))
else:
form=PostForm()
return render_to_response('myapp/addpost.html', {'form': form}, context )
urls.py
urlpatterns = patterns(
'',
...
url(r'^profile/(?P<id>\d+)/$', views.profile, name='profile'),
url(r'^addpost/$', views.add_post, name='add_post'),
)
You've misdiagnosed the problem. It is nothing to do with redirecting; it occurring in the template itself, because you have used {% url 'addpost' %} instead of {% url 'add_post' %}.
Just redirect, you don't need to do a render_to_response.
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
#login_required
def add_post(request):
....
if form.is_valid():
....
return redirect(reverse('profile', args=[request.user.pk]))

Reverse for '' with arguments '()' and keyword arguments '{}' not found.

I write a message board,When user leave message and success back to the page
I want to alert('sucess leaving message,Thank you very much.')
I found a method is to use return redirect(reverse(...))
But there is an error when I try :
Reverse for '/maininfo/#5thPage' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
Please help me ,Thank you .
views.py
def maininfo(request):
return render(request, 'zh_tw/maininfo.html',)
def create_post(request):
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
form.save()
# return HttpResponseRedirect('/maininfo/#5thPage')
return redirect(reverse("/maininfo/#5thPage"), {"alert":'sucess leaving message,Thank you very much.'})
return render(request, "zh_tw/maininfo.html",{'form': form,'anchor':'#5thPage'})
urls.py
urlpatterns = patterns('',url(r'^maininfo/$', views.maininfo, name='maininfo'),)
template: zh_tw/contact.html
(this is an anchor page included by zh_tw/maininfo.html)
<script type="text/javascript">
$( document ).ready(function() {
{% if alert %}
alert('{{alert}}');
{% endif %}
});
</script>
The argument for reverse is the name or the view module in the urlpattern. In your case, it should be
views.maininfo
or
'maininfo'
Moreover, $ indicates the end of a string in Python regular expression. Thus you may not be able to resolve the '/maininfo/#5thPage' using the pattern ^maininfo/$. Find more info here :https://docs.djangoproject.com/en/dev/topics/http/urls/ .

Categories