Im pretty new to both python and django , currently reading the Python Crash Course by Eric Matthes . Im trying to code a simple learning log , but im having some issues adding new topics using the django form . Heres the code:
urls.py:
from django.urls import path , re_path
from . import views
urlpatterns = [
#Home page
path('', views.index, name='index'),
path('topics/', views.topics , name='topics'),
re_path(r'^topics/(?P<topic_id>\d+)/$' , views.topic , name = 'topic'),
re_path(r'^new_topic/$' , views.new_topic , name = 'new_topic')
]
app_name = 'learning_logs'
part of view.py:
def new_topic(request):
if request.method != 'POST':
form = TopicForm
else:
form = TopicForm(request.POST)
if form.is_valid():
form.save
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {'form' : form}
return render(request , 'learning_logs/new_topic.html' , context)
new_topic.html:
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>Added a new topic:</p>
<form action="{% url 'learning_logs:new_topic' %}" method="post">
{% csrf_token %}
{{form.as_p}}
<button name='submit'>add topic</button>
</form>
{% endblock content %}
topics.html:
{% extends 'learning_logs/base.html' %}
{% block content %}
<p>Topics</p>
<ul>
{% for topic in topics %}
<li>{{topic}}</li>
{% empty %}
<li>No topics have been added yet.</li>
{% endfor %}
</ul>
Add a new topic:
{% endblock content %}
the brackets are missing. It should form.save() as bkrop mentioned
Related
I am working on CS50 Project 1 dealing with Django. In urls.py I have two paths that take strings as input, but neither work, and I receive a NoReverseError message.
urls.py code
urlpatterns = [
path("", views.index, name="index"),
path("edit_entry/<str:title>/", views.edit_entry, name = "edit_entry"),
path("search/", views.search, name = "search"),
path("wiki/<str:title>/", views.get_entry, name = "get_entry"),
path("create_entry", views.create_entry, name = "create_entry")
]
views.get_entry code
def get_entry(request, title):
exists = util.get_entry(title)
if exists is None:
return render(request, "encyclopedia/get_entry.html", {
"entry": "Entry Does Not Exist"
})
else:
entry = markdown(util.get_entry(title))
return render(request, "encyclopedia/get_entry.html", {
"entry": entry
})
views.edit_entry code (edit_entry actually has some more work that needs to be done to it)
def edit_entry(request, title):
if request.method == "POST":
form = NewEditEntryForm(request.POST)
if form.is_valid():
title = form.cleaned_data["title"]
content = form.cleaned_data["content"]
util.save_entry(title, content)
return HttpRespnseRedirect("/wiki/" + title)
else: return render(request, "encyclopedia/edit_entry.html",{
"form": NewEditEntryForm() })
The error message
NoReverseMatch at /wiki/Css/
Reverse for 'edit_entry' with keyword arguments '{'title': ''}' not found. 1 pattern(s) tried: ['edit_entry/(?P<title>[^/]+)/$']
Your help would greatly be appreciated. Thank you!
Templates
get_entry.html
{% extends "encyclopedia/layout.html" %}
{% block title %}
Encyclopedia
{% endblock %}
{% block body %}
<p>
{{ entry|safe }}
</p>
Edit This Entry
{% endblock %}
edit_entry.html
{% extends "encyclopedia/layout.html" %}
{% block title %}
Edit Entry
{% endblock %}
{% block body %}
<h1>Edit {{ title }}</h1>
<form action = "{% url 'edit_entry' title=title %}" method = "POST"></form>
{% csrf_token %}
{{ form }}
<input type = submit value = "Save">
</form>
{% endblock %}
I figured it out. I had to remove title=title from the hrefs in the templates and make it a hard coded url with a variable.
I'm new to Django and I'm making wiki website based on markdown. I am having one problem. Django can't match the path in html to urls.py. It happens when I try to open wiki entries. It gives me the following error. I have already passed the parameter to 'page', I honestly have no idea what to do.
Using the URLconf defined in wiki.urls, Django tried these URL patterns, in this order:
admin/
[name='index']
wiki/<str:page> [name='page']
search [name='search']
create [name='create']
addentry [name='add_entry']
nomatches [name='nomatches']
results [name='results']
edit/<str:page> [name='edit']
random [name='random']
The current path, { url 'page' entry }, didn't match any of these.
Please, tell me how can I fix this.
index. html:
{% extends "encyclopedia/layout.html" %}
{% block title %}
Encyclopedia
{% endblock %}
{% block body %}
<h1>All Pages</h1>
<ul>
{% for entry in entries %}
<li>{{ entry }}</li>
{% endfor %}
</ul>
{% endblock %}
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:page>", views.viewpage, name="page"),
path("search", views.search, name="search"),
path("create", views.create, name="create"),
path("addentry", views.add_entry, name="add_entry"),
path("nomatches", views.search, name="nomatches"),
path("results", views.search, name="results"),
path("edit/<str:page>", views.edit, name="edit"),
path("random", views.random, name="random")
]
part of views.py:
def index(request):
return render(request, "encyclopedia/index.html", {
"entries": util.list_entries()
})
def viewpage(request, page):
content = util.get_entry(page)
return render(request, "encyclopedia/page.html", {
"content": markdown2.markdown(content),
"title":page
})
page.html
{% extends "encyclopedia/layout.html" %}
{% block title %}
{{ title }}
{% endblock %}
{% block body %}
edit
<h1>{{ title }}</h1>
{{ content|safe }}
{% endblock %}
Since the URL for 'page' is 'wiki/<str: page>' you need to define a get_absolute_url method on your class model that contains the object in question, so do add this method in the models.py class that contains page:
def get_absolute_url(self):
return reverse('page',kwargs={str:self.str})
Then, in the template, you can refer to it as
{% object.get_absolute_url%}.
This is the error I get when clicking on Edit post under any one of the posts. Would appreciate any help as all this django stuff is confusing me but trying my best to learn. My new post function works and clicking blog/posts to go to the overview page for the blog or to look at all the posts works as well.
NoReverseMatch at /edit_post/1/
Reverse for 'posts' with arguments '(1,)' not found. 1 pattern(s) tried: ['posts/$']
Error during template rendering
In template C:\Users\seng\Desktop\Python projects\c19\nineteen_one\blogs\templates\blogs\base.html, error at line 0
urls.py
"""Defines url paterns for blogs"""
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns =[
#Home page
path('', views.index, name='index'),
# Page that shows all posts/
path('posts/', views.posts, name='posts'),
#Page for adding a new blogpost
path('new_post/', views.new_post, name='new_post'),
#Page for editing a post
#maybe remove the id?
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
views.py
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogPostForm
# Create your views here.
def index(request):
"""The home page for blogs"""
return render(request, 'blogs/index.html')
def posts(request):
"""Show all blogposts"""
posts = BlogPost.objects.order_by('date_added')
context = {'posts': posts}
return render(request, 'blogs/posts.html', context)
def new_post(request):
"""Add a new blogpost"""
if request.method != 'POST':
#No data submitted; create a blank form.
form = BlogPostForm()
else:
#POST data submitted, process data
form = BlogPostForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:posts')
#Display a blank or invalid form
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
"""Edit existing post"""
post = BlogPost.objects.get(id=post_id)
if request.method != "POST":
#Initial request, pre-fill form with the current post
form = BlogPostForm(instance=post)
else:
#Post data submitted, process data
form = BlogPostForm(instance=post, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:posts', post_id=post.id)
context = {'post':post, 'form':form}
return render(request, 'blogs/edit_post.html', context)
forms.py
from django import forms
from .models import BlogPost
class BlogPostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['text', 'title']
labels = {'text':'This is the text box', 'title' :"Title here"}
edit_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>{{ post }}</p>
<p>Edit post:</p>
<form action="{% url 'blogs:edit_post' post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save changes</button>
</form>
{% endblock content %}
posts.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Posts</p>
<ul>
{% for post in posts %}
<li>
<p>{{ post }}</p>
<p>
Edit post
</p>
</li>
{% empty %}
<li>No posts have been added yet.</li>
{% endfor %}
</ul>
Add a new post
{% endblock content %}
new_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Add a new post:</p>
<form action="{% url 'blogs:new_post' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Add post</button>
</form>
{% endblock content %}
The issue is with this line in edit_post.html:
<p>{{ post }}</p>
If you are editing the post with id 1, then this link is to the url /posts/1. But that has no match in your urls.py file.
Either you need to remove the post.id parameter from the link, or create a view and a corresponding path in urls.py for this link.
I am fairly new to Django and for my certification, I am working on cloning Wikipedia. I was able to get the wiki and editing commands to work but having difficulties creating new entries. This is my function to create a new entry:
** Main urls.py**
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("encyclopedia.urls"))
]
urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path ("wiki/<str:title>", views.entry, name="entry"),
path ("edit/<str:title>", views.edit, name="edit"),
path ("create/<str:title>", views.create, name="create")
]
views.py
class Post(forms.Form):
title = forms.CharField(label= "Title")
textarea = forms.CharField(widget=forms.Textarea(), label='')
def create(request, title):
if request.method == "POST":
form = Post(request.POST)
if form.is_valid():
title = form.cleaned_data["title"]
textarea = form.cleaned_data['textarea']
entries : util.list_entries()
if title in entries:
return render(request, "encyclopedia/error.html", {
"form": Search(),
"message": "Page already exists",
"type": "exists"
})
else:
util.save_entry(title,textarea)
page=util.get_entry(title)
page_converted = md.convert(page)
return render(request, "encyclopedia/create.html", {
"form": Search(),
'page': page_converted,
"title": title
})
else:
return render(request, "encyclopedia/create.html", {
"form": Search(),
"post": Post()
})
MY TEMPLATE
Creating a new entry
{% extends "encyclopedia/layout.html" %}
{% block title %}
Create
{% endblock %}
{% block body %}
<form method="post" action="{% url 'create' %}">
{% csrf_token %}
<h4 class="display-2">Create new page:</h4>
<h6 class="post-title">Title: {{post.title}}</h6>
{{post.textarea}}
<br>
<input class="save btn btn-info" type="submit" value="Save"/>
</form>
{% endblock %}
Pop an error if the page already exists/not found
{% extends "encyclopedia/layout.html" %}
{% block title %}
Error
{% endblock %}
{% block body %}
<h1 class="display-2 error">{{message}}</h1>
{% if type == "not_found" %}
<h3>The page {{title}} cannot be found.</h3>
{% endif %}
{% if type == "exists" %}
<h3>The page {{title}} already exists.</h3>
{% endif %}
{% endblock %}
THE ERROR THAT DJANGO RETURNS
NoReverseMatch at /create/HTML
Reverse for 'create' with no arguments not found. 1 pattern(s) tried: ['create/(?P<title>[^/]+)$']
Request Method: GET
Request URL: http://localhost:8000/create/HTML
Django Version: 3.1.2
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'create' with no arguments not found. 1 pattern(s) tried: ['create/(?P<title>[^/]+)$']
Exception Location: /usr/local/Cellar/python#3.8/3.8.6/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/urls/resolvers.py, line 685, in _reverse_with_prefix
Python Executable: /usr/local/bin/python
Python Version: 3.8.6
Python Path:
['/Users/amertoukan/Desktop/Projects/cs50/Django/wiki',
'/usr/local/Cellar/python#3.8/3.8.6/Frameworks/Python.framework/Versions/3.8/lib/python38.zip',
'/usr/local/Cellar/python#3.8/3.8.6/Frameworks/Python.framework/Versions/3.8/lib/python3.8',
'/usr/local/Cellar/python#3.8/3.8.6/Frameworks/Python.framework/Versions/3.8/lib/python3.8/lib-dynload',
'/Users/amertoukan/Library/Python/3.8/lib/python/site-packages',
'/usr/local/Cellar/python#3.8/3.8.6/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages
What am I doing wrong? Thank you sm in advance.
The reason is that when you create a new entry, you do not have title yet.
You are getting the title and save it to edit it later.
path ("create/", views.create, name="create")
and in views.py
def create(request): # no title.
I'm trying to make a website that lets visitors search for books using another search engine. I have a script that takes a query, and returns some HTML with the results of the search, but I'm struggling to make a front end for this. I am using django because it seemed like the best option when I started, but now I am going in circles and I can't figure out how to make this thing - I'm just getting overwhelmed because the different tutorials and documentation that I'm reading all go into the advanced stuff before I can get the basic thing working.
Do I need separate search and results templates? Right now I'm getting the error The view book_search.views.search didn't return an HttpResponse object. It returned None instead.
How can I fix this error and/or design this whole thing better?
Here's what I have so far (the script that returns the results in html is pull.py):
The views and urls are from inside the book_search app.
views.py:
from django.shortcuts import render
from django.http import HttpResponse
from . import pull
from .forms import SearchForm
def index(request):
return HttpResponse("Welcome to the index page")
def test_search(request):
context = {'query': 'test query'}
return render(request, 'book_search/search.html', context)
def search(request):
if request.method == "GET":
form = SearchForm(request.GET)
if form.is_valid():
query = form.cleaned_data['query']
results = pull.main(query)
context = {'query': query, 'form': form, 'results': results}
return render(request, 'book_search/results.html', context)
apps.py:
from django.apps import AppConfig
class BookSearchConfig(AppConfig):
name = 'book_search'
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('index', views.index, name='index'),
path('test', views.test_search, name='test_search'),
path('', views.search, name='search'),
]
forms.py:
class SearchForm(forms.Form):
query = forms.CharField(label='Search', max_length=200)
template base.html:
<html>
<head>
</head>
<body>
<form method="GET" action="/search/">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
{% block content %}{% endblock %}
</body>
</html>
template results.html:
{% block content %}
{% results %}
{% endblock content %}
Since we guessed that form isn't valid (because no POST handler - you do not send anything to the form) and wrong indentation gives None response, now you can fix reference before assignment:
def search(request):
if request.method == "GET":
form = SearchForm()
context = {'form': form}
elif request.method == "POST":
form = SearchForm(request.POST)
if form.is_valid():
query = form.cleaned_data['query']
results = pull.main(query)
context = {'query': query, 'form': form, 'results': results}
return render(request, 'book_search/results.html', context)
and render errors in results.html template by putting this:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}