I am very new to Django and have been following through the blog tutorial from the book: "Django by Example."
The code below should return all blog posts with a status of "published" but it refuses to work. What appears to be the correct page loads up using the list.html code but there are no posts showing. I have double checked and I am creating posts with the admin site with the status set to "published." I am not sure if the problem is with the template, model, views or URLs so I am including it all here:
Models.py:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
from django.core.urlresolvers import reverse
#Data model class for creating posts table enrties in database
#Custom manager. Limits returned querysets to ones with published status
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset()\
.filter(status='published') #super used to call get_queryset method from parent class as it is currently being
#overridden here.
class Post(models.Model):
STATUS_CHOICES = (('draft', 'Draft'), ('published', 'Published'),)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique_for_date='publish') #A field for use in building urls
#slug = models.SlugField(slugify(title))
author = models.ForeignKey(User, related_name='blog_posts') #Each post written by a user and a user can write many posts
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
objects = models.Manager() #The default manager
published = PublishedManager() #Custom manager
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.publish.year, self.publish.strftime('%m'),self.publish.strftime('%d'), self.slug])
views.py:
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.objects.all()
return render(request, 'blog/post/list.html', {'Posts': 'posts'})
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post, status='published', publish__year=year, publish__month=month, publish__day=day)
return render(request, 'blog/post/detail.html', {'post':post})
URLs.py
from django.conf.urls import url
from . import views
urlpatterns = [
# post views
url(r'^$', views.post_list, name='post_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/'\
r'(?P<post>[-\w]+)/$', views.post_detail, name='post_detail'),
Templates base.html:
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/blog.css" %}" rel="stylesheet">
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="sidebar">
<h2>My Site site</h2>
<p>This site is all about me</p>
</div>
</body>
</html>
detail.html:
{% extends "blog/base.html" %}
{% block title %}My Blog{% endblock %}
{% block content %}
<h1>Blog</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">Published{{ post.publish }} by {{ post.author }}</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% endblock %}
You need to use Post.published.all() to use your custom manager then in your dict you are doing 'Posts' with a capital P you might want to try lowercase as your view is using posts. Then also the value for it was a string instead of the variable posts. So something like this should work
def post_list(request):
posts = Post.published.all()
return render(request, 'blog/post/list.html', {'posts': posts})
You are passing in a string as your context object data:
return render(request, 'blog/post/list.html', {'Posts': 'posts'})
Needs to be
return render(request, 'blog/post/list.html', {'Posts': posts})
It also still isn't going to work since you have in your view and aren't calling the manager method. You have:
posts = Post.objects.all()
You need to use your customer manager.
I found the answer - all posts in the database are in the "draft" status, and status='published' is registered in the PublishedManager. Change status=''draft" and everything will be OK!
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
am using django 2.0 and here is the problem
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/blog/post-detail/
Raised by: blog.views.post_detail
No Post matches the given query.
here is the blog/urls
from django.urls import path,include
from .import views
urlpatterns = [
path('blog/',views.post_list,name="post_list"),
path('blog/post-detail/',views.post_detail,name="post_detail"),
]
and views.py
from django.shortcuts import render,get_object_or_404
from.models import Post
# Create your views here.
def post_list(request):
object_list=Post.objects.all()
context={
'object_list': object_list,
}
return render(request,"blog.html",context)
def post_detail(request,slug=None):
post=get_object_or_404(Post,slug=slug)
context={
'post':post,
}
return render(request,"post_detail.html",context)
and the post_detail.html
{% extends "base.html" %}
{% load static %}
{% block seo_title %}{% endblock %}
{% block seo_description %}{% endblock %}
{% block Content %}
<article>
<div class="embed-responsive embed-responsive-16by9">
<img src="images/blog1.jpg" alt="" />
</div>
<div class="post-content">
<h2>{{post.title}}</h2>
<div>
{{post.created}} Author {{Post.user}}
<hr/>
<p>{{post.body}}</p>
</article>
{% endblock Content %}
CAN ANYONE HELP ON THIS THE ONLY PROBLEM I SEE THAT SLUG THING I MUST HAVE CONFUSED SOMEWHERE
blog.html
<!-- Blog -->
<div class="blog">
<div class="row">
<div class="col-sm-8">
<!-- Blog Post-->
{% for obj in object_list %}
{% if obj.status == 'Published' %}
<article>
<div class="embed-responsive embed-responsive-16by9">
<img src="images/blog1.jpg" alt="" />
</div>
<div class="post-content">
<h2>{{obj.title}}</h2>
<div>
{{obj.created}} Author {{obj.user}}
<hr/>
<p>{{obj.body}}</p>
<a class="mtr-btn button-navy ripple" href= "{% url 'post_detail' slug= post.slug %}">Continue reading →</a><br>
</div>
</article>
{% endif %}
{% endfor %}
The view post_detail(request,slug=None) is to view details about a post. So your URL pattern is incorrect:
path('blog/post-detail/<slug:slug>',views.post_detail,name="post_detail"),
To call it in templates, the simpler and correct way to do is:
<a class="mtr-btn button-navy ripple" href= "{% url 'post_detail' obj.slug %}">Continue reading →</a><br>
</div>
#FOLLOW THIS PROCEDURE.I HOPE IT HELPS YOU OR ANY ONE ELSE IN THE FUTURE
# At blog/urls.py
from django.urls import path
from .views import (post_list, post_detail)
urlspatterns = [
path('blog/', post_list, name='post-list'),
path('<str:slug>/blog/post-detail/', post_detail, name='post-detail'),
]
#At blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.objects.all()
template_name = blog/post_list.html
context = {'posts':posts}
return render(request, template_name, context)
def post_detail(request, slug):
posts = get_object_or_404(Post, slug=slug)
template_name = blog/post_detail.html
context = {'posts':posts}
return render(request, template_name, context)
# At the template/blog/post_list.html
{% block content %}
{% for post in posts %}
<article>
<div>
<small>{{ post.created_on|date:"F d, Y" }}</small>
<h2>{{ post.title }}</h2>
<p >{{ post.body }}</p>
</div>
</article>
{% endfor %}
{% endblock content %}
# At template/blog/post_detail.html
<article>
<div>
<small>{{ posts.created_on|date:"F d, Y" }}</small>
<h2>{{ posts.title }}</h2>
<p>{{ posts.body }}</p>
</div>
</article>
#The above code should fix the the issue properly.
If your a following Django 3 By Example Book can check this soltuion because I had the same problem.
Book teach how to create Post with a slug attribute with
models.SlugField and unique_for_date='pusblish' condition.
Then you add some posts from admin site.
Then you add some posts from admin site but then in admin.py book teach how to edit the register with
prepopulated_fields = {'sulg':('title',)}.
Finally, book teach you how to edit posts.
This is a problem because never
going to find a post created. So, the solution for me was delete
posts and the create new ones.
here my code:
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique_for_date='publish')
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='blog_posts')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
objects = models.Manager() # The default manager.
published = PublishedManager() # Our custom manager.
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.publish.day, self.slug])
admin.py
from django.contrib import admin
from .models import Post
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish', 'status')
list_filter = ('status', 'created', 'publish', 'author')
search_fields = ('title', 'body')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'publish'
ordering = ('status', 'publish')
views.py
from django.shortcuts import render, get_object_or_404
# another views...
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
# post views
path('', views.PostListView.as_view(), name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
]
my_site/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls', namespace='blog')),
]
i created a blog
this is my models.py configurations:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
# Create your models here.
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset()\
.filter(status='published')
class post(models.Model):
STATUS_CHOICE=(
('draft','DRAFT'),
('published','Published'),
('admin','admin'),
)
title=models.CharField(max_length=250,null=True)
author=models.ForeignKey(User,related_name='blog_posts',null=True)
slug=models.SlugField(max_length=250,unique_for_date='publish',null=True)
body=models.TextField(default='')
publish=models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True,null=True)
updated =models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,
choices =STATUS_CHOICE,
default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',args=[self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%dz'),
self.slug])
and this is my views.py:
from django.shortcuts import render
from .models import post
# Create your views here.
def post_list(request):
posts= post.published.all()
return render(request,'blog/post/list.html',{posts:posts})
def post_detail(request,year,month,day,post):
post=get_object_or_404(post,slug=post,
status = 'published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,'blog/post/index.html',{'post':post})
and this is my base.html:
{%load staticfiles%}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}
<link rel="stylesheet" href={% static "/css/blog.css"%}>
{% endblock %}
</title>
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="sidebar">
<h2>my blog</h2>
<h3>this blog</h3>
</div>
</body>
</html>
and my list.html file:
{% extends "blog/base.html" %}
{% block title %}My blog{% endblock %}
{% block content %}
<h1>My Blog</h1>
{% for post in posts %}
<h2>
{{ post.title }}
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% endblock %}
and this is my urls.py (app folder)
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$',views.post_list,name = 'post_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\W]+)/$',
views.post_detail,
name='post_detail'),
]
and this is my urls.py file of my project folder:
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('myblog.urls',namespace='blog',app_name='blog')),
]
and i have added some post objects using admin user but when i tried to access the page the expected output according to the tutorial looks like this:
enter image description here
but instead my output was :
enter image description here
Firstly, the key in your context dictionary should be the string 'posts', not the variable posts, as #ABDUL pointed out in the comments.
return render(request,'blog/post/list.html',{'posts':posts})
Then you need to fix the NoReverseMatch error. In your get_absolute_url method, you have %dz. It should be '%d'. Remove the z.
def get_absolute_url(self):
return reverse('blog:post_detail',args=[self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%d'),
self.slug])
I'm learning django framework writing a blog. I've added some posts in django-admin and I want to show them on web.
MODELS.PY
from django.db import models
from django.utils import timezone
from django.core.urlresolvers import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager,
self).get_queryset()\
.filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Roboczy'),
('publish', 'Opublikowany')
)
title = models.CharField(max_length=300)
slug = models.SlugField(max_length=300, unique_for_date='publish')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=20,
choices=STATUS_CHOICES,
default='draft')
object = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%d'),
self.slug])
VIEWS.PY
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.published.all()
return render(request,
'blog/post/list.html',
{'posts': posts})
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status ='published',
publish_year=year,
publish_month=month,
publish_day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
URLS.PY at BLOG APP
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$'
r'(?P<post>[-\w]+)/$',
views.post_detail,
name='post_detail'),
]
URLS.PY (project level)
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^blog/', include('blog.urls',
namespace='blog',
app_name='blog')),
]
list.html
{% extends "blog/base.html" %}
{% block title %}My Blog {% endblock %}
{% block content %}
<h1>Mój BLOG</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p>
Opublikowane {{ post.publish }} przez {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks}}
{% endfor %}
{% endblock %}
I don't know why these posts aren't shown on list.html. I think the mistake is in get_absolute_url.
Instead of posts = Post.published.all()
Try
posts = Post.objects.all()
Ok it's work i must change posts = Post.objects.all() and on list.htlm
<a href="{{ post.get_absolute_url }}">
to
<a href="{{ posts }}">
Urlpatterns are wrong.
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$'
r'(?P<post>[-\w]+)/$',
views.post_detail,
name='post_detail'),
According to the views the url pattern should be:
url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<post>[-\w]+)/$',
views.post_detail,
name='post_detail'),
Also, Views are wrong:
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status ='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
Please note that query fields are publish__year (not publish_year), publish___month(not publish_month) and publish__date( not publish_date)
Once you make these changes, the get_absolute_url will also work fine.
I don't know if you want to use Post.objects.all() or Post.published.all(). Ideally, it should be Post.published.all() because in general, only published posts are displayed.
i'm a beginner in Django and i have a problem ….
I created an application(name :PQR) with 3 models (Patient / Question / Reply)
I want to see a views with the name of the patient at the top, under this, all questions availables and if applicable, the answers next to the question (some patient may have empty reply / no reply).
I know how to display the answers for a patient but I would like to display EVERY questions and if available, I want to provide the reply but I don't know how to write this in my view?
This is my model :
Class Patient(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
def listReply(self):
replies = Reply.objects.filter(patient= self.id)
return replies
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 str(self.reply_text)
This is my view :
from django.shortcuts import render, get_object_or_404
from django.template import RequestContext
from .models import Patient, Question, Reply
def list(request):
list_patient = Patient.objects.order_by('name') context = RequestContext(request, {'list_patient':list_patient,'welcome': 'Welcome on my page Django !',
})
return render(request, 'PQR/list.html', context)
def detail(request, patient_id):
patient = get_object_or_404(Patient, pk=patient_id)
list_question = Question.objects.all()
Replies4MyPatient = Reply.objects.filter(patient=patient_id)
return render(request, 'PQR/detail.html', locals())
And 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.detail, name ='detail_patient'),
And this is my template :
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'Forum/style.css' %}" />
<div>
<h1>Patient details : {{ patient }}</h1>
</div>
<fieldset>
{% csrf_token %}
{% for reply in Replies4MyPatient %}
</br><abcd>{{ reply.question }}</abcd></br>
</br>
<li>{{ reply }}</li>
{% endfor %}
</fieldset></br>
<a href="{% url 'list_patient' %}"/> <input type="button" value="Look Back"/>
Thanks you for your help !
The function render builds the html to return with a template and a context. In your template PQR/detail.html, you use {{ patient }} and Replies4MyPatient. You need to build a context with these values and to pass it to render
def detail(request, patient_id):
patient = get_object_or_404(Patient, pk=patient_id)
list_question = Question.objects.all()
Replies4MyPatient = Reply.objects.filter(patient=patient_id)
context = {'patient' : patient, 'Replies4MyPatient' : Replies4MyPatient}
return render(request, 'PQR/detail.html', context=context)