Note: there's a similar question to mine, there're a few differences in our code, and I tried the solutions to his question, didn't work for me.
I'm working on a blog using Django, I'm trying to add an edit_post feature but when I go to localhost:8000 it shows NoReverseMatch, the problem is related to the post's id, I'm trying to create a home page that shows the post's title and it's content.
here'e my code:
models.py
from django.db import models
# Create your models here.
class BlogPost(models.Model):
title = models.CharField(max_length=20)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
urls.py
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# page for adding a new post
path('new_post/', views.new_post, name='new_post'),
# page for editing a post
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
index.html
{% block content %}
<p>My personal Blog</p>
Add a new post
<ul>
{% for p in posts %}
# the problem is probably here
<li>{{ p.title }}</li>
<li>{{ p.text }}</li>
<p>
Edit post
</p>
{% endfor %}
</ul>
{% endblock content %}
edit_post.html
{% block content %}
<p>Edit post:</p>
<form action="{% url 'blogs:edit_post' post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submet">Save changes</button>
</form>
{% endblock content %}
new_post.html
{% block content %}
<P>Add a new post:</P>
<form action="{% url 'blogs:new_post' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submet">Add post</button>
</form>
{% endblock content %}
views.py
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogPostForm
# Create your views here.
def index(request):
posts = BlogPost.objects.order_by('date_added')
context = {'posts': posts}
return render(request, 'blogs/index.html', context)
def new_post(request):
"""Add a new post."""
if request.method != 'POST':
form = BlogPostForm()
else:
form = BlogPostForm(data=request.POST)
if form.is_valid():
new_p = form.save()
return redirect('blogs:index')
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
post = BlogPost.objects.get(id=post_id)
if request.method != 'POST':
form = BlogPostForm(instance=post)
else:
form = BlogPostForm(instance=post, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:index', post_id=post.id)
context = {'post': post, 'index': index, '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 = ['title', 'text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols':80})}
The problem is with the arguments of the url you are creating on index.html, you are looping posts as p in html so try to change:
Edit post
With
Edit post
Related
Currently working through the Python Crash Course Django section I've got everything but the edit posts page working. I added the edit post link under each post but this error now displays when you try to view the homepage:
Reverse for 'edit_post' with no arguments not found. 1 pattern(s) tried: ['edit_post/(?P<post_id>[0-9]+)/$']
Here is the code I've been using.
from django.db import models
# Create your models here.
class BlogPost(models.Model):
"""A topic the user is learning about"""
title = models.CharField(max_length=200)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""A place for the user to create a blog post"""
return self.title
Views
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogForm
# Create your views here.
def index(request):
"""The home page for Blog"""
return render(request, 'blogs/index.html')
def blogposts(request):
"""Show all blogposts"""
blogposts = BlogPost.objects.order_by('date_added')
context = {'blogposts': blogposts}
return render(request, 'blogs/blogposts.html', context)
def new_post(request):
"""Add a new post"""
if request.method != 'POST':
# No data submitted, create a blank form
form = BlogForm()
else:
# POST data submitted; process data
form = BlogForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:blogposts')
# Display a blank or invalid form
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
current_entry = BlogPost.objects.get(id=post_id)
if request.method != 'POST':
# Initial request; pre-fill form with current entry
form = BlogForm(instance=current_entry)
else:
form = BlogForm(instance=current_entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:index')
context = {'post':post, 'form':form}
return render(request, 'blogs/edit_post.html', context)
URLs
"""Defines URL patterns 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 topics
path('blogposts/', views.blogposts, name='blogposts'),
# Page that displays a single post
path('new_post/', views.new_post, name='new_post'),
# Page for editing a post
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
blogposts.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Blog Posts</p>
<ul>
{% for blogpost in blogposts %}
<h1>{{ blogpost }}</h1>
<p>{{ blogpost.body }}</p>
Edit post
{% empty %}
<li>No blogs have been posted yet</li>
{% endfor %}
</ul>
Create a new post
{% endblock content %}
edit_post.html
{% extends "blogs/base.html" %}
{% block content %}
<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 %}
You need to pass the id of the blog post you want to edit.
So in your blogposts.html try:
"{% url 'blogs:edit_post' blogpost.pk %}"
Thank you for taking the time to help! I've been stuck for hours. I'm learning django by going through this fantastic youtube video: https://www.youtube.com/watch?v=sm1mokevMWk&t=4252s. I believe I copied the code from the video exactly, and I double and triple checked it. Yet, despite declaring method = "post" in "create".html django consistently uses a get response. WHY?!
#urls.py
from django.urls import path
from . import views
urlpatterns = [
path('<int:id>', views.index, name='index'),
path("",views.home, name = 'home'),
path("create/", views.create, name="create"),
]
#views.py
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from .models import ToDoList, Item
from .forms import CreateNewList
def index(response, id):
ls = ToDoList.objects.get(id=id)
return render(response, 'main/list.html', {"ls":ls})
def home(response):
return render(response, "main/home.html", {})
def create(response):
print(response.method)
if response.method == "POST":
form = CreateNewList(response.POST)
if form.is_valid():
n = form.cleaned_data['name']
t = ToDoList(name=n)
t.save()
return HttpResponseRedirect("/%i" %t.id)
else:
form = CreateNewList()
return render(response, "main/create.html", {"form":form})
#create.html
{% extends 'main/base.html' %}
{% block title %} Create New List {% endblock %}
{% block content %}
Create Pages
<form method="post" action="/create/">
{{form.as_p}}
<button type="submit", name ="save" >Create New</button>
</form>
{% endblock %}
#base.html
<html>
<head>
<title>{% block title %}Jeff's website{% endblock %}</title>
</head>
<body>
<div id="content", name="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
#home.html
{% extends 'main/base.html' %}
{% block title %}
Home
{% endblock %}
{% block content %}
<h1>Home Page</h1>
{% endblock %}
#models.py
from django.db import models
class ToDoList(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Item(models.Model):
todolist = models.ForeignKey(ToDoList, on_delete=models.CASCADE)
text = models.CharField(max_length=300)
complete = models.BooleanField()
def __str__(self):
return self.text
You need to perform a GET request first to display your form and then , you make a post request for the submit, that why you check the request method .
if response.method == "POST" => The form is already displayed and we need to submit it
else we need to display our form
I want to have a form (webpage) for the model ImpCalendar so I can edit it's data.
The url should have the calendar_id (primary key), which i set in the urls.py
The model (ImpCalendar) has a ForeignKey to Establishments. I do not use that foreignkey in the view/form so i don't know if it is relevant.
If i do in views.py;
return render(request, 'importer/calendaredit.html', {'form': calendar})
i do see the data on a page, but not a (edit) form. Just the data, not the fill-in fields.
When i do
return render(request, 'importer/calendaredit.html', {'form': form})
which sounds logical to me, I get the error
django.urls.exceptions.NoReverseMatch: Reverse for 'calendaredit' with arguments '('',)' not found. 1 pattern(s) tried: ['importer\\/calendar\\/(?P<calendar_id>[0-9]+)\\/$']
It seems to me, the value returned for the calendar_id is now forms-data (html) which it can not do anything with. But i don't know what I am doing wrong. It has to do something with the html code and the values being transported to it, but i am last.
models.py
class Impcalendar(models.Model):
establishment = models.ForeignKey(Establishments, on_delete=SET_NULL, null=True)
url = models.CharField(max_length=255)
comment = models.CharField(max_length=255, null=True, blank=True)
status = models.IntegerField(null=True, blank=True)
def __str__(self):
return str(self.establishment)
forms.py
from django import forms
import datetime
from importer.models import Impcalendar, Establishments
class ImpcalendarForm(forms.ModelForm):
class Meta:
model = Impcalendar
fields = ['id', 'url']
urls.py
from django.urls import path
from importer import views
urlpatterns = [
path('', views.index, name='index'),
path('calendar/<int:calendar_id>/', views.calendaredit, name='calendaredit')
]
views.py
def calendaredit(request, calendar_id):
calendar = get_object_or_404(Impcalendar, pk=calendar_id)
print (calendar.url)
if request.method == 'POST':
form = ImpcalendarForm(request.POST, instance=calendar)
if form.is_valid():
calendar.save()
else:
form = ImpcalendarForm(request.POST or None, instance=calendar)
return render(request, 'importer/calendaredit.html', {'form': form})
calendaredit.html
{% extends 'importer/base.html' %}
{% block content %}
<h1>{{ form.id }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'calendaredit' form.id %}" method="post">
<div class="fieldWrapper">
{% csrf_token %}
{{ form.id }}
{{ form.url }}
</div>
<input type="submit" value="Save" />
</form>
{% endblock %}
You need to pass both things, calling them what they are, and reference the calendar not the form.
return render(request, 'importer/calendaredit.html', {'form': form, 'calendar': calendar})
...
<form action="{% url 'calendaredit' calendar.id %}" method="post">
For some reason, my forms.py doesn't view any of the fields, instead, it only shows the 'Add' button and I don't know what to do anymore. I'd really appreciate if someone who knows what they're doing could tell me what I did, or didn't do.
Please note that I'm new to Django, thank you.
Here's my views.py:
from django.shortcuts import render
from django.utils import timezone
from .models import Measurement
from .forms import MeasurementForm
from django.views import generic
class IndexView(generic.ListView):
model = Measurement
context_object_name = 'measurement_list'
template_name = 'index.html'
queryset = Measurement.objects.all()
def new_measurement(request):
if request.method == "POST":
form = MeasurementForm(request.POST)
if form.is_valid():
measurement = form.save(commit=False)
measurement.measurement_date = timezone.now()
measurement.save()
else:
form = MeasurementForm()
return render(request, 'index.html', {'form': form})
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
]
forms.py:
from django import forms
from .models import Measurement
class MeasurementForm(forms.ModelForm):
class Meta:
model = Measurement
fields = ('measurement_value', 'measurement_unit')
index.html:
{% extends "base.html" %}
{% block content %}
<h1>Climate Measurement Tool</h1>
<h2>Add a new measurement</h2>
<form method="POST" class="post-form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save">Add</button>
</form>
<h2>Measurements</h2>
{% if measurement_list %}
<ul>
{% for measurement in measurement_list %}
<li>
<p>{{ measurement }}</p>
</li>
{% endfor %}
</ul>
{% else %}
<p>No measurements yet</p>
{% endif %}
{% endblock %}
The new_measurement() view correctly initializes a form instance and passes it to the template.
Unfortunately, that view is never called.
urls.py defines only one url, handled by IndexView.as_view(), which does not pass a form instance to the template.
I want to know how to retrieve answers already made in my text fields because there is no ways to retrieve the answers already registered!
This is my models :
class Patient(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name + ' [' + str(self.id) + ']'
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __unicode__(self):
return self.question_text
class Reply(models.Model):
question = models.ForeignKey(Question)
patient = models.ForeignKey(Patient)
reply_text = models.CharField(max_length=200)
def __unicode__(self):
return self.reply_text
This is my template (formDynamic.html) :
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'Forum/style.css' %}" />
<div>
<h1>Patient details : {{ patient }}</h1>
</div>
form-included-into-question-template -->
<form action="success" method="post">
{% csrf_token %}
<fieldset>
{% block content %}
{% for question in questions %}
<h2><abcd>{{ question }}</abcd> <h6>{{ question.pub_date }}</h6></h2>
{% for reply in form %}
{{ form }}
{% endfor %}
{% endfor %}
{% endblock %}
</fieldset>
<input type="submit" value="Submit"/>
</form>
<a href="{% url 'list_patient' %}"/> <input type="button" value="Look Back"/>
This is my urls :
from django.conf.urls import url
from .import views
urlpatterns = [
url(r'^$', views.list, name ='list_patient'),
url(r'^(?P<patient_id>[0-9]+)/patient/$', views.save_reply, name ='detail_patient'),
#url(r'^(?P<patient_id>[0-9]+)/patient/success$', 'success', name ='success'),
]
This is my forms.py :
from django.forms import ModelForm
from django import forms
from .models import Reply
class ReplyForm(ModelForm):
class Meta:
model = Reply
fields = ['reply_text']
This is my views.py :
def save_reply(request, patient_id):
patient = get_object_or_404(Patient, pk=patient_id)
questions = Question.objects.all()
if request.method == 'POST':
form = Replyform(request.POST)
if form.is_valid():
new_obj = form.save(commit=False)
new_obj.creator = request.user
u = Question.objects.get(pk=id)
new_obj.reply_to = u
new_obj.save()
return HttpResponseRedirect('/success')
else:
form = ReplyForm()
return render_to_response('PQR/formDynamic.html', {'form': form, 'questions': questions, 'patient': patient,}, context_instance=RequestContext(request))
def success(request):
return HttpResponse ('<p>Success</p>')
I can not retrieve the answers already registered and run my post method to save my answers and return me the URL /success.
My post method does not work as well as my redirect to my url / success. Thanks you for your help !
I don't understand your question, but the reason you can't submit your form is that it is posting to a non-existent destination: the action attribute in the form HTML tag needs to be an actual URL. If you want to use a view name then do so via the {% url %} tag:
<form action="{% url "success" patient_id=patient.id %}" method="post">