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 %}"
Related
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
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
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')
I use a simple form to edit the name of a invoice (invoice_text). When I submit the changes it redirects back to index page. The problem is that the index page is showing the old records. This is only in Firefox. Internet Explorer shows the changes directly. F5 helps, but of course it needs to show the new (edited) information.
forms.py
class InvoiceForm(ModelForm):
class Meta:
model = Invoice
fields = ('Invoice_text',)
views.py
def index(request):
latest_invoice_list = Invoice.objects.order_by('-pub_date')[:5]
context = {'latest_invoice_list': latest_invoice_list}
return render(request, 'invoices/index.html', context)
def invoice_edit(request, pk):
obj = get_object_or_404(Invoice, pk=pk)
if request.method == "POST":
form = InvoiceForm(request.POST, instance=obj)
if form.is_valid():
obj = form.save(commit=False)
obj.Invoice_text = request.POST['Invoice_text']
obj.save()
return HttpResponseRedirect('/invoices/')
else:
form = InvoiceForm(instance=obj)
return render(request, 'polls/edit_Invoice.html', {'form': form})
Index.html template
{% if latest_invoice_list %}
<ul>
{% for invoice in latest_invoice_list %}
<li>{{ invoice.invoice_text }} | edit</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
This is strange, but you should be able to use the #never_cache decorator to prevent it:
from django.views.decorators.cache import never_cache
#never_cache
def index(request):
....
I created a panel in open stack. What I want to do is produce a simple page that when loaded it makes a call to get a status and then puts that status (good, bad, warning) in a page with a combo box and have a submit button that when hit gets back to my python code so I can do what I want based on that status.
They way I did it was a form with a ChoiceField. I have a class IndexView (views.APIViews) from open stack I believe. It has a get_data method called where I can go get the data and return a context. I haven't found an example where you set the something in the context passing the status to a form somehow. Like context['status'] = "Good"..
What I get is when the page is loaded get_data is called and I do nothing. The submit button is there but no "Status: (combo box)" I hit Submit and status is called with a POST. form.is_valid() is false and it returns a render with a form created passing in request.POST. This gets a form to appears and I can hit Submit and I get a call to status with a .POST and is_valid is true and it redirects to thanks like I want. It's just that I can't get data into the form in get_data.
Here is my code:
Views.py
from horizon import views
from django import forms
from django.shortcuts import render
from django.http import HttpResponseRedirect
STATUS_CHOICES = (
("GOOD", "Good"),
("BAD", "Bad"),
("COMPROMISED", "Compromised")
)
def thanks(request):
return render(request, 'pinehurst_dashboard/ssa_panel/sent.html')
class SsaForm(forms.Form):
status = forms.ChoiceField(choices = STATUS_CHOICES, label="Status:")
def status(request):
print("STATUS CALLED method=",request.method)
if request.method == 'POST': # If the form has been submitted...
form = SsaForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
print("redirect to THANKS!")
return HttpResponseRedirect('thanks/') # Redirect after POST
else:
print("form.is_valid = false")
else:
print("Requesting form\n")
form = SsaForm(initial = {"status", "BAD"}) # An unbound form
return render(request, 'pinehurst_dashboard/ssa_panel/index.html', {
'form': form,
})
class IndexView(views.APIView):
# A very simple class-based view...
template_name = 'my_dashboard/ssa_panel/index.html'
def get_data(self, request, context, *args, **kwargs):
print("GET_DATA Called", context)
# Add data to the context here...
return context
Urls.py
from django.conf.urls import patterns
from django.conf.urls import url
from openstack_dashboard.dashboards.my_dashboard.ssa_panel import views
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'status/$', views.status),
url(r'thanks/$', views.thanks),
)
nothing in models.py
my_dashboard/ssa_panel/index.html
{% extends 'pinehurst_dashboard/base.html' %}
{% load i18n %}
{% block title %}{% trans "Pinehurst" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("SSA Panel") %}
{% endblock page_header %}
{% block pinehurst_dashboard_main %}
<form action="status/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}