My blog has the capacity to make posts. I wanted to have a feature where i can update/edit the blog and when i try to implement the feature i run into the following error;
NoReverseMatch at /post/1/ Reverse for 'post_edit' with arguments
'('',)' not found. 1 pattern(s) tried: ['post/(?P[0-9]+)/edit/$']
I know what line is causing the problem:
/post_detail.html
+Edit Blog Post
without the line on top, i get no errors. I am just a begginer learning Django and i cannot make any sense of why this is not working. It is suggested in the tutorial i am following.
/urls.py
urlpatterns = [
path('post/<int:pk>/edit/', BlogUpdateView.as_view(), name='post_edit'), # new
path('post/new/', BlogCreateView.as_view(), name='post_new'),
path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'),
path('', BlogListView.as_view(), name='home'),
]
/post_detail.html
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>
{{ my_posts.title }}
</h2>
<p>
{{ my_posts.body }}
</p>
</div>
+Edit Blog Post
{% endblock content %}
views.py
class BlogListView(ListView):
model = Post
template_name = 'home.html'
class BlogDetailView(DeleteView):
model = Post
context_object_name = 'my_posts'
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Post
template_name = 'post_new.html'
fields = '__all__'
class BlogUpdateView(UpdateView):
model = Post
template_name = 'post_edit.html'
fields = ['title', 'body']
/models.py
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
The name of your context object is: context_object_name = 'my_posts', not 'post'. Therefore the object is my_posts in your template.
The link should thus be:
+Edit Blog Post
Try:
path(r'post/<int:pk>/edit/', BlogUpdateView.as_view(), name='post_edit'), # new
I added an r in front of your url.
We could write model class name "post" in lowercase or "object" with or without context_object_name to make it work.
<a
+ edit post
or
+ edit post
at post_detail.html
Related
Can anyone please help. I am currently working through a project where I am attempting to create a website for a fictitious restaurant, including an online booking form.
I am getting the following error message:
TypeError at /bookings/
'OnlineForm' object is not callable
I have watched a number of videos and read through the Django documentation and I still have no idea what I am doing wrong. I am new to Django so this is all learning for me. Any advice you can give would be hugely appreciated. Thank you in advance
This is my code:
view.py:
class BookingForm(FormView):
form_class = OnlineForm()
args = {}
def booking_view(self, request):
if request.method == 'POST':
form = OnlineForm(request.POST)
return render(request, 'bookings.html')
models.py
OCCASION_CHOICE = (
('Birthday', 'BIRTHDAY'),
('Anniversary', 'ANNIVERSARY'),
('Graduation', 'GRADUATION'),
('Communion', 'COMMUNION'),
('Confirmation', 'CONFIRMATION'),
('Christening', 'CHRISTENING'),
('Date Night', 'DATE NIGHT'),
)
class Booking(models.Model):
name = models.CharField(max_length=50)
email_address = models.EmailField()
phone = models.IntegerField()
number_of_people = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(10)],default='1', help_text='For parties of more than 10, please call us on 021 4569 782')
date = models.DateField()
time = models.TimeField()
occasion = models.CharField(max_length=100, choices=OCCASION_CHOICE, default='Birthday')
def __str__(self):
return self.name
forms.py:
from django.forms import ModelForm
from .models import Booking
class OnlineForm(ModelForm):
class Meta:
model = Booking
fields = '__all__'
urls.py:
from . import views
from .views import BookingForm
from django.urls import path
app_name = 'bookingsystem'
urlpatterns = [
path('', views.Home.as_view(), name='home'),
path('bookings/', BookingForm.as_view(), name='bookings'),
path('menus/', views.Menus.as_view(), name='menus'),
path('edit_bookings', views.editBooking.as_view(), name='edit_bookings'),
]
bookings.html:
{% extends "base.html" %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{form}}
<button id="submit-button" class="btn btn-success">Book Now</button>
</form>
{%endblock%}
According to django description, of FormView you do not have an option of defining your own POST method. Rewriting your view to
class BookingForm(FormView):
template_name = 'bookings.html'
form_class = OnlineForm
will solve the issue. Though you'll need to add a form_valid method to define actions to carryout when a form with valid data is submitted.
I have been working on a blog site using django and I made a way to add post within the home page without going to the admin page but when I post using the new way I get this error
This is my models.py file
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=255)
title_tag = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField(max_length=3500)
def __str__(self):
return (self.title + " | " + str(self.author))
def get_absolute_url(self):
return reverse("article-view", args=(str(self.id)))
This is the views.py file
from django.views.generic import ListView, DetailView, CreateView
from .models import Post
class HomeView(ListView):
model = Post
template_name = "home.html"
class ArticleDetailView(DetailView):
model = Post
template_name = "detail_view.html"
class AddPostView(CreateView):
model = Post
template_name = "add_post.html"
fields = "__all__"
This is the polls/urls.py
from django.urls import path
from .views import HomeView, ArticleDetailView, AddPostView
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('article/<int:pk>', ArticleDetailView.as_view(), name='article-view'),
path('add_post/', AddPostView.as_view(), name='add_post'),
]
This is the add_post.html file
{% extends 'base.html' %}
{% block content %}
<head>
<title>Adding Post</title>
</head>
<h1>Add Blog Posts</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-secondary">Post</button>
</form>
{% endblock %}
Thank you.
Okay, so it looks like this is caused by the model's get_absolute_url reverse args=(). I changed the below code in models.py from:
def get_absolute_url(self):
return reverse("article-view", args=(str(self.id)))
Into
def get_absolute_url(self):
return reverse("article-view", args=[self.id])
The problem seems to be args=(), it is iterating over the str(self.id). So id=10 would actually be returned as a tuple (1,0). I also removed the str() around the self.id since the URL takes in an int.
I have a Post model with a whole bunch of posts. I also have a log model which has a foreign key field to the Post model. Essentially the Log model stores log entries for the Posts in the Post model (basically Post comments). Everything was going great. I have been using CBV for my post models and I used a CBV to List my log entries. I then added a link to redirect me to the Log CreateView using the following anchor tag:
<a class="btn" href="{% url 'log-create' post_id=logs.post_id %}">Add Entry</a>
When the NoReverse errors started occuring. When I change the log.post_id to 1, the page loads correctly. This leads me to believe that the log.post_id is not returning any value. Another thought that I had was that because this anchor tag was on the LogListView there were multiple log entries so it didn't know which post_id to use. But I used the get_queryset function on this view to make sure that only logs related to a single post are returned. In my mind the log.post_id should work.
My models are:
class Post(models.Model):
title = models.CharField(max_length=100, blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
overview = models.TextField(blank=True)
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.id})
def __str__(self):
return self.title
class Log(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
log_entry = models.TextField(max_length=500, blank=True)
log_author = models.ForeignKey(User, on_delete=models.CASCADE)
date_posted = models.DateTimeField(default=timezone.now)
My Views:
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView
from .models import Post, Log
from django.http import HttpResponseRedirect
from django.contrib.auth.mixins import LoginRequiredMixin
class LogListView(ListView):
model = Log
template_name = 'blog/log_entries.html'
context_object_name = 'logs'
ordering = ['-date_posted']
def get_queryset(self):
self.post = get_object_or_404(Post, log=self.kwargs['pk'])
return Log.objects.filter(post=self.post)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(LogListView, self).get_context_data(**kwargs)
# Add in a QuerySet of all images related to post
context['post'] = Post.objects.all()
return context
class LogCreateView(LoginRequiredMixin, CreateView):
model = Log
fields = [
'log_entry'
]
def form_valid(self, form):
form.instance.log_author = self.request.user
post = Post.objects.get(pk=self.kwargs['post_id'])
return super().form_valid(form)
My urls.py
from django.urls import path, include
from . import views
from .views import LogListView, LogCreateView
urlpatterns = [
path('', PostListView.as_view(), name='blog-home'),
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('post/new/', PostCreateView.as_view(), name='post-create'),
path('post/<int:pk>/log/', LogListView.as_view(), name='log-list'),
path('post/<int:post_id>/log/new/', LogCreateView.as_view(), name='log-create'),
]
And Lastly, my template:
{% extends "blog/base.html"%}
{% block body_class %} home-section {% endblock %}
{% block content %}
<div class="container">
<h2>Log Entries</h2>
{% for log in logs %}
<div class="row">
<article class="content-section">
<div class="article-metadata log-metadata">
<a class="mr-2" href="{% url 'profile' user=log.log_author %}">{{ log.log_author }}</a>
<small class="text-muted">{{ log.date_posted|date:"d F Y" }}</small>
{% if request.user.is_authenticated and request.user == log.log_author %}
<ion-icon name="trash"></ion-icon>
{% endif %}
</div>
<p class="">{{ log.log_entry }}</p>
</article>
</div>
{% endfor %}
<a class="btn" href="{% url 'log-create' post_id=logs.post_id %}">Add Entry</a>
</div>
{% endblock content %}
I think I am correctly passing a parameter to the url. this is evident from when I make post_id=1. But I am not sure I am calling it correctly. Any help on this issue would be great thanks.
UPDATED: I edited my context_object_name in my LogListView to logs to make the for loop less confusing. Essentially I am trying to get one anchor tag at the bottom of all the log entries to redirect to the Add entry page.
I suggest an approach that renders a link only if there are objects available, using the first element:
</article>
</div>
{% if forloop.first %}<a class="btn" href="{% url 'log-create' post_id=log.post.id %}">Add Entry</a>{% endif %}
{% endfor %}
This log.post.id means get id of post object (foreign key) of log object.
I need to pass id from one template to another template. In template i am iterating over one model
{% for project in all_projects %}
<h3>{{ project.name }}</h3>
{% endfor %}
This going to one template where my url looks like
url(r'^$', views.ProjectsListView.as_view(), name='index'),
url(r'^platforms/$', views.PlatformsIndexView.as_view(), name='platforms'),
url(r'^platforms/nodes/$', views.PlatformsNodesListView.as_view(), name='platforms_list'),
Browser url that i have is http://127.0.0.1:8000/platforms/?project=1
that's ok good. But from second template i need to send third template another parametrs and filters. So how do i can get id of project?
I can not send now project id to third template because i am not iterating over it. How to remember id of project?
views.py
class ProjectsListView(ListView):
template_name = 'project/projects.html'
model = Project
context_object_name = 'all_projects'
class PlatformsIndexView(TemplateView):
template_name = 'project/platforms.html'
class PlatformsNodesListView(ListView):
template_name = 'project/general.html'
model = Platform
context_object_name = 'all_platforms'
def get_queryset(self):
queryset = super().get_queryset()
type_filter = self.request.GET.get('type')
project_filter = self.request.GET.get('project')
if type_filter in [Platform.BACKEND, Platform.ANDROID, Platform.IOS, Platform.FRONTEND]:
queryset = queryset.filter(type=type_filter)
if project_filter:
queryset = queryset.filter(project__id__exact=project_filter)
else:
raise Http404
return queryset
Please explain me.
Thank you in advance
Im doing my first Django site myself after going through several tutorials and running into some errors that I can't figure out what the problem is as they are simple page requests.
I was trying to make a category detail view e.g. 127.0.0.1:8000/news and Ive followed the same setup as other pages such as the index and post detail which have worked fine but this is giving a 404.
here are my files
models.py
from django.db import models
from django.core.urlresolvers import reverse
class EntryQuerySet(models.QuerySet):
def published(self):
return self.filter(publish=True)
class Blog(models.Model):
title = models.CharField(max_length = 200)
slug = models.SlugField(max_length = 100, db_index = True)
body = models.TextField()
publish = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey('blog.category')
objects = EntryQuerySet.as_manager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', kwargs={'slug':self.slug})
class Meta:
verbose_name = 'Blog entry'
verbose_name_plural = 'Blog entries'
ordering = ['-created']
class Category(models.Model):
cat_title = models.CharField(max_length = 200, db_index = True)
cat_slug = models.SlugField(max_length = 100, db_index = True)
def __str__(self):
return self.cat_title
def get_absolute_url(self):
return reverse('category_detail', kwargs={'cat_slug':self.cat_slug})
class Meta:
verbose_name = 'Category'
verbose_name_plural = 'Categories'
views.py
from django.views import generic
from . import models
class index_view(generic.ListView):
queryset = models.Blog.objects.published()
template_name = 'index.html'
class post_view(generic.DetailView):
model = models.Blog
template_name = 'post_view.html'
class category_view(generic.ListView):
model = models.Category
template_name = 'category_view.html'
class category_detail_view(generic.DetailView):
model = models.Category
template_name = 'category_detail_view.html'
class About_page(generic.DetailView):
template_name = 'about.html'
app urls.py
from django.conf.urls import url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^$', views.index_view.as_view(), name='index'),
url(r'^categories/$', views.category_view.as_view(), name='category_detail'),
url(r'^(?P<slug>\S+)$', views.post_view.as_view(), name='post_detail'),
url(r'^(?P<cat_slug>\S+)$', views.category_detail_view.as_view(), name='category_detail_view'),
url(r'^about/$', views.About_page.as_view(), name='about'),
this is the category detail page 'category_detail_view.html'
{% extends 'base.html' %}
{% block title %} The category detail view page {% endblock %}
{% block category_detail %}
{% for cat_title in object_list %}
<ul>
<li>{{ category.cat_title }}</li>
{% endfor %}
</ul>
{% endblock %}
and the about page
{% extends 'base.html' %}
<h2>This is the about page</h2>
both of these pages return this error message
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/about/
Raised by: blog.views.post_view
No Blog entry found matching the query
I dont understand why 'blog.post_view' is being raised when neither of these templates refer to the post_view.
I have an index page with all published posts listed, a categories page with all categories listed and a post detail page all of which work fine and are almost exactly the same as these views and templates.
When Django resolves the url /about/, it goes through your url patterns in order. It matches the post_detail url pattern, so runs the post_view, treating about as a slug. Since you don't have any posts with the slug about, you get the 404 error.
One solution is to move the about url pattern above the post_detail pattern. You should also change the category url pattern, otherwise it won't work. For example, you could do:
url(r'^about/$', views.About_page.as_view(), name='about'),
url(r'^(?P<slug>\S+)$', views.post_view.as_view(), name='post_detail'),
url(r'^categories/(?P<cat_slug>\S+)$', views.category_detail_view.as_view(), name='category_detail_view'),