I have created a class in the models.py containing the information of articles I want to insert in a website
from django.db import models
from django.urls import reverse
class Article(models.Model):
"""
Model representing an article.
"""
title = models.CharField(max_length=200)
authors = models.CharField(max_length=200)
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the article')
content = models.TextField(max_length=100000)
def __str__(self):
"""
String for representing the Model object.
"""
return self.title
def get_absolute_url(self):
"""
Returns the url to access a detail record for this article.
"""
return reverse('article-detail', args=[str(self.id)])
After that, I have inserted an article using the admin panel of Django and saved it.
Then, I have created the index.html shown below calling the articles in the database
<!DOCTYPE html>
<html lang="en">
<head>
{% block title %}{% endblock %}
</head>
<body>
{% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
{% block content %}<!-- default content text (typically empty) -->
<!-- Articles -->
<div class="articles">
<h1>Titolo: {{ article.title }}</h1>
<p><strong>Autori:</strong> {{ article.authors }}</p>
<p><strong>Riepilogo:</strong> {{ article.summary }}</p>
<p><strong>Testo:</strong> {{ article.content }}</p>
</div>
{% endblock %}
</body>
</html>
But the article is not shown despite being in the database (see prints below)
EDIT1: inserted views.py as requested
from django.shortcuts import render
from .models import Article
# Create your views here.
def index(request):
"""
View function for home page of site.
"""
# Render the HTML template index.html with the data in the context variable
return render(
request,
'index.html',
)
You are not including any articls in your template context:
return render(
request,
'index.html',
)
You could include the articles in the template context with:
articles = Article.objects.all()
return render(
request,
'index.html',
{'articles': articles}
)
Then in the template you need to loop through the articles.
<!-- Articles -->
<div class="articles">
{% for article in articles %}
<h1>Titolo: {{ article.title }}</h1>
<p><strong>Autori:</strong> {{ article.authors }}</p>
<p><strong>Riepilogo:</strong> {{ article.summary }}</p>
<p><strong>Testo:</strong> {{ article.content }}</p>
{% endfor %}
</div>
Related
I am trying to create a way to edit individual blog posts from their individual html. Here are the relevant files and trace back. I am somewhat understanding that the issue lies in blog_post.id being due to the fact that blog_post has not carried over from the for loop on blog_posts.html. I have read up on others having this issue and they all structured their pages to have the edit button being inside the original for loop, which makes sense in hindsight. BUT now that I have run into this issue, I'm determined to understand how I can solve it without going back and restructuring my pages to align with the others I saw.
urls.py
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.index, name='index'),
path('blog_posts/', views.blog_posts, name='blog_posts'),
path('blog_posts/<int:blog_post_id>/', views.blog_post, name='blog_post'),
path('new_blog_post/', views.new_blog_post, name='new_blog_post'),
path('edit_blog_post/<int:blog_post_id>/', views.edit_blog_post, name='edit_blog_post'),
]
views.py
from .models import BlogPost
from .forms import BlogPostForm
def index(request):
"""Home page for Blog."""
return render(request, 'blogs/index.html')
def blog_posts(request):
"""Show all Blog Posts."""
blog_posts = BlogPost.objects.order_by('date_added')
context = {'blog_posts': blog_posts}
return render(request, 'blogs/blog_posts.html', context)
def blog_post(request, blog_post_id):
"""Show details of an individual blog post."""
blog_post = BlogPost.objects.get(id=blog_post_id)
title = blog_post.title
id = blog_post_id
date = blog_post.date_added
text = blog_post.text
context = {'title': title, 'text': text, 'date': date}
return render(request, 'blogs/blog_post.html', context)
def new_blog_post(request):
"""Add a new blog post"""
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:blog_posts')
# Display a blank or invalid form.
context = {'form': form}
return render(request, 'blogs/new_blog_post.html', context)
def edit_blog_post(request, blog_post_id):
"""Edit an existing blog post's title or text."""
blog_post = BlogPost.objects.get(id=blog_post_id)
if request.method != 'POST':
# Initial request, prefill with the current data.
form = BlogPostForm(instance=blog_post)
else:
# POST data submitted; process new data.
form = BlogPostForm(instance=blog_post, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:blog_post', blog_post_id=blog_post.id)
context = {'blog_post': blog_post, 'form': form}
return render(request, 'blogs/edit_blog_post.html', context)
models.py
from django.db import models
class BlogPost(models.Model):
"""A post the user is posting on their blog."""
title = models.CharField(max_length=200)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a string representation of the model"""
return f"{self.title.title()}"
blog_posts.html
{% extends 'blogs/base.html' %}
{% block content %}
<p>Blog Posts</p>
<ul>
{% for blog_post in blog_posts %}
<li>
{{ blog_post }}
</li>
{% empty %}
<li>No posts have been made yet.</li>
{% endfor %}
</ul>
Add a new blog post
{% endblock content %}
blog_post.html
{% extends 'blogs/base.html' %}
{% block content %}
<p>Blog Post: {{ title }}</p>
<p>Entry:</p>
<p>{{ text }}</p>
<p>{{ date }}</p>
<p>
Edit Blog Post
</p>
{% endblock content %}
edit_blog_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>
{{ blog_post }}
</p>
<p>Edit Blog Post</p>
<form action="{% url 'blogs:edit_blog_post' blog_post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save Changes</button>
</form>
{% endblock content %}
Reverse for 'edit_blog_post' with arguments '('',)' not found. 1 pattern(s) tried: ['edit_blog_post/(?P<blog_post_id>[0-9]+)/\Z']
3 {% block content %}
4
5 <p>Blog Post: {{ title }}</p>
6
7 <p>Entry:</p>
8
9 <p>{{ text }}</p>
10 <p>{{ date }}</p>
11
12 <p>
13 Edit Blog Post
14 </p>
15
16 {% endblock content %}
If I've read the question correctly, You're getting the error becuase you are not providing the necessary ID to the URL construction part of your template.
You're separating out the elements (date, content etc) to send to the template, but not passing the ID at the same time. You could send the ID in as a separate context variable, but that's extra typing for no real reward.
It's easiest to pass in the post itself via context and refer to its attributes in the template - I think it makes it easier to read also. That way the ID is there when you need to contruct the edit link, and if you change the model to possess extra fields, you don't need to convert and add to the context as the whole post is already there.
views.py
def blog_post(request, blog_post_id):
"""Show details of an individual blog post."""
blog_post = BlogPost.objects.get(id=blog_post_id) #this is all we need
context = {"blog_post_context": blog_post}
return render(request, 'blogs/blog_post.html', context)
blog_post.html
{% extends 'blogs/base.html' %}
{% block content %}
<p>Blog Post: {{ blog_post_context.title }}</p>
<p>Entry:</p>
<p>{{ blog_post_context.text }}</p>
<p>{{ blog_post_context.date }}</p>
<p>
Edit Blog Post
</p>
{% endblock content %}
If that all works, look into using get_object_or_404 rather than Post.objects.get for some additional robustness.
I assume you got the error when you try visiting the blog_post.html page. If I'm correct, then here's an approach you could take...
In your views.py
def blog_post(request, blog_post_id):
"""Show details of an individual blog post."""
# blog_post = BlogPost.objects.get(id=blog_post_id)
blog_post = get_object_or_404(id=blog_post_id) # Recommended
# Commented lines below are somewhat not necessary...
# title = blog_post.title
# id = blog_post_id
# date = blog_post.date_added
# text = blog_post.text
context = {'blog_post': blog_post}
return render(request, 'blogs/blog_post.html', context)
edit_blog_post.html is expecting an object called blog_post to be able to access the blog_post.id for {% url 'blogs:edit_blog_post' blog_post.id %}.
Now within the edit_blog_post.html file.
{% block content %}
<p>Blog Post: {{ blog_post.title }}</p>
<p>Entry:</p>
<p>{{ blog_post.text }}</p>
<p>{{ blog_post.date_added }}</p>
<p>
Edit Blog Post
</p>
{% endblock content %}
Still needs working answer.
I have added three apps to my django website: application, blog, and feedback. All three have the same problem: when I click a link, or enter a URL, to any of them, I get a 404 error.
I'm attaching code and other documentation below for one of the problem addons. For further context, if necessary, my full code can be found at https://github.com/kkerwin1/pensdnd.
Directory structure
(venv) kris#adjutant:~/venv/pensdnd$ tree -if
.
./application
./application/admin.py
./application/apps.py
./application/forms.py
./application/__init__.py
./application/migrations
./application/models.py
./application/templates
./application/templates/application.html
./application/templates/application_thanks.html
./application/tests.py
./application/urls.py
./application/views.py
./blog
./blog/admin.py
./blog/apps.py
./blog/models.py
./blog/templates
./blog/templates/blog_list.html
./blog/templates/blog_post.html
./blog/tests.py
./blog/urls.py
./blog/views.py
./feedback
./feedback/admin.py
./feedback/apps.py
./feedback/forms.py
./feedback/models.py
./feedback/templates
./feedback/templates/feedback.html
./feedback/templates/feedback_thanks.html
./feedback/tests.py
./feedback/urls.py
./feedback/views.py
./manage.py
./pensdnd
./pensdnd/settings.py
./pensdnd/static
./pensdnd/static/css
./pensdnd/static/css/main.css
./pensdnd/static/html
./pensdnd/static/html/arvon_rules.html
./pensdnd/static/html/be_a_dm.html
./pensdnd/static/html/community_rules.html
./pensdnd/static/html/guild_rules.html
./pensdnd/static/html/index.html
./pensdnd/static/html/volunteer.html
./pensdnd/static/img
./pensdnd/static/img/carbon_fibre.png
./pensdnd/static/img/github_icon.png
./pensdnd/static/js
./pensdnd/static/misc
./pensdnd/static/templates
./pensdnd/static/templates/base.html
./pensdnd/static/templates/partials
./pensdnd/static/templates/partials/blogbar.html
./pensdnd/static/templates/partials/feedback.html
./pensdnd/static/templates/partials/footer.html
./pensdnd/static/templates/partials/navbar.html
./pensdnd/static/templates/partials/newsbar.html
./pensdnd/static/vid
./pensdnd/urls.py
./pensdnd/views.py
./pensdnd/wsgi.py
./requirements.txt
./pensdnd/urls.py
from django.contrib import admin
from django.urls import path, include
from . import views
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', views.HomePageView.as_view()),
path('admin/', admin.site.urls),
path('be_a_dm/', views.BeADM.as_view()),
path('blog/', include('blog.urls')),
path('feedback/', include('feedback.urls')),
path('application/', include('application.urls')),
path('guild_rules/', views.GuildRules.as_view()),
path('community_rules/', views.CommunityRules.as_view()),
path('arvon_rules/', views.ArvonRules.as_view()),
path('volunteer/', views.Volunteer.as_view()),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
./blog/urls.py
from . import views
from django.urls import path
urlpatterns = [
path('blog/', views.PostList.as_view()),
path('blog/<slug:slug>/', views.PostDetail.as_view(), name='post_detail'),
]
./blog/views.py
from django.shortcuts import render
from .models import Post
from django.views import generic
# Create your views here.
class PostList(generic.ListView):
queryset = Post.objects.filter(status=1).order_by('-created_on')
template_name = 'templates/blog_list.html'
class PostDetail(generic.DetailView):
model = Post
template_name = 'templates/blog_post.html'
./blog/models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
./blogs/templates/blog_list.html
{% extends 'static/templates/base.html' %}
<!doctype html>
<html lang="en">
<head>
<title>
{% block title %}
PensiveDND :: Blog Posts
{% endblock %}
</title>
</head>
<body>
{% block pagecontent %}
<section>
{% for post in post_list %}
<article>
<h3>{{ post.title }}</h3>
<p>{{ post.author }} | {{ post.created_on }}</p>
<p>{{ post.content|slice:":200" }}
Read More
</article>
</section>
{% endblock %}
</body>
</html>
./blogs/templates/blog_post.html
{% extends 'static/templates/base.html' %}
<!doctype html>
<html lang="en">
<head>
<title>
{% block title %}
PensiveDND :: Blog :: {{ post.title }}
{% endblock %}
</title>
</head>
<body>
{% block pagecontent %}
<section>
<h2>{{ post.title }}</h2>
<p>{{ post.author }} | {{ post.created_on }}</p>
<p>{{ post.content | safe }}</p>
</section>
{% endblock %}
</body>
</html>
In "pensdnd/urls.py", you are missing the trailing slashes after your app name
for example
path('feedback', include('feedback.urls')),
should be
path('feedback/', include('feedback.urls')),
Unable to access html files. There are no errors in your urls.py file. At least for the blog app. When I run the code, I don't get a 404 error with different edits. According to the Github codes, I changed the DIRS section in the templates field under settings.py to 'templates' and moved the html files you used in your blog application here. There was no problem. Editing all your code can be difficult, but that's where the problem lies.(Note that I only control the blog app.)
also, you will get an error because you don't use {% endfor %}.
{% for post in post_list %}
<article>
<h3>{{ post.title }}</h3>
<p>{{ post.author }} | {{ post.created_on }}</p>
<p>{{ post.content|slice:":200" }}
Read More
</article>
If you have set templates location, you should just use template_name = 'blog_list.html instead of template_name = 'templates/blog_list.html'.
Please check these things again. As I said, the problem is caused by the use of static and templates. not urls.
I am using the "keyone" column in the database to filter entries. So far in the code i have written i am successfully able to render template with "keyone = 2" values. what should i write in a new template file, and how should i modify existing views.py so that when the template file renders it contains a list of links , each link for each value of "keyone" , when i click on the link say "keyone = 2", the selected entries should get rendered in home.html
models.py
# app/models.py
from django.db import models
from django.urls import reverse # new
class Post(models.Model):
text = models.TextField()
def __str__(self):
return self.text[:50]
keyone = models.IntegerField(default = '777')
def get_absolute_url(self): # new
return reverse('post_detail', args=[str(self.id)])
views.py
def HomePageView(request):
key2select = Post.objects.filter(keyone=2)
return render(request, 'home.html', {
'key2select': key2select,
})
home.html
<ul>
{% for post in key2select %}
<li>{{ post.keyone }}   {{ post.text }}</li>
{% endfor %}
</ul>
sample database
desired rendering
Firstly, we need to get all keyone values in the DB, to be passed to home.html.
Then in home.html, we need a navbar or somewhere else to put all these links which represent all the keyone values.
So the code would be like:
models.py
# app.models.py would remain the same
views.py
def homePageView(request, key):
key2select = Post.objects.filter(keyone=key)
keyones = Post.objects.distinct('keyone')
return render(request, 'home.html', {
'key2select': key2select,
'keyones': keyones
})
You can check the distinct() in the Django Docs to get distinct values of a column in DB
home.html
<!-- home.html -->
<nav>
<ul>
{% for key in keyones %}
<li>somthing {{key}} something</li>
{% endfor %}
</ul>
</nav>
...
<ul>
{% for post in key2select %}
<li>{{ post.keyone }}   {{ post.text }}</li>
{% endfor %}
</ul>
As we passed the key to the url in the nav link, we need to change the url pattern to catch this.
urls.py
urlpatterns =[
...
path('home/<int:key>/', views.homePageView, name='home')
...
]
May be I'm not understand you problem, if you'r looking for create a list of link code should be
<ul>
{% for post in key2select %}
<a href="{% url "post_detail" post.id %}"><li>{{ post.keyone }}   {{ post.text }}</li><a/>
{% endfor %}
</ul>
This will contain every post link with list item
thanks #sheng-zhuang for providing the solution. Here is the working code with some slight modifications for my benefit.
I created a new template select.html and here is the logic -
Views.py
class IndexView(TemplateView):
template_name = 'index.html'
def SelectView(request):
keyones = Post.objects.values_list('keyone',flat=True).distinct()
return render(request, 'select.html', {
'keyones': keyones
})
def HomePageView(request, key):
key2select = Post.objects.filter(keyone=key)
return render(request, 'home.html', {
'key2select': key2select,
})
index.html
<header>
Select<br />
Post
</header>
select.html
<nav>
<ul>
{% for key in keyones %}
<li>Keyone value = {{key}} </li>
{% endfor %}
</ul>
</nav>
home.html
<header>
Select<br />
Post
</header>
<br /><br /><br /><br />
<ul>
{% for post in key2select %}
<li>{{ post.keyone }}   {{ post.text }}</li>
{% endfor %}
</ul>
urls.py
path('', IndexView.as_view(), name='index'),
path('select/', SelectView, name='select'),
path('home/<int:key>/', HomePageView, name='home')
I am designing a video rendering kids website.
The app has parent categories for eg: Cartoons, Education shows etc. Each category has multiple posts such as Jungle_book,Duck_tales etc for cartoons.
Each post has multiple episodes.
I am using generic views(listview, Detailview) for views.
Here are my Models.py
from django.db import models
from personal.models import Post
class cartoons_post(models.Model):
category= models.ForeignKey(Post, on_delete=models.CASCADE)
title = models.CharField(max_length = 140)
thumbnail=models.ImageField()
date=models.DateField()
def __unicode__(self):
return self.title
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"id": self.id})
class post_episode(models.Model):
post_id= models.ForeignKey(cartoons_post, on_delete=models.CASCADE)
title = models.CharField(max_length = 140)
thumbnail=models.ImageField()
date=models.DateField()
video=models.FileField()
def __unicode__(self):
return self.title
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"id": self.id})
Here is my urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from cartoons.models import cartoons_post,post_episode
from django.contrib.auth.decorators import login_required
urlpatterns = [
url(r'^$', login_required(ListView.as_view(
queryset=cartoons_post.objects.all().order_by("-date")[:10],
template_name="cartoons/cartoons.html"))),
url(r'^(?P<pk>\d+)$', login_required(ListView.as_view(
queryset=post_episode.objects.filter(post_id=1).order_by("-date"),
template_name="cartoons/post.html"))),
url(r'^(?P<pk>\d+\d+)$',login_required(DetailView.as_view(
model = post_episode,
template_name="cartoons/post_episode.html"))),
]
Here are my three templates
cartoons.html
{% extends "personal/header.html" %}
{% load staticfiles %}
{% block content %}
{% for cartoons_post in object_list %}
<img src= "{{cartoons_post.thumbnail.url}}" width="200" height="220">
{% endfor %}
{% endblock %}
post.html
{% extends "personal/header.html" %}
{% load staticfiles %}
{% block content %}
{% for post_episode in object_list %}
<img src= "{{post_episode.thumbnail.url}}" width="200" height="220">
{% endfor %}
{% endblock %}
post_episode.html
{% extends "personal/header.html" %}
{% load staticfiles %}
{% block content %}
<div class="container-fluid_cartoons">
<h3>{{post_episode.title}}</h3>
<video width="850" height="500" controls>
<source src="{{post_episdoe.video.url}}" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
{% endblock %}
Issues
- Only cartoons.html is working fine.
Once I click on an individual post the relevant post.html shows all the episode uploaded rather than episodes pertaining to individual post only.
Once I click on an episode, nothing happens.
You should consider creating views.py file rather than using generic views in urls.py. I think issue is with following line
url(r'^(?P<pk>\d+)$',login_required(ListView.as_view(queryset=post_episode.objects.filter(post_id=1).order_by("-date"),template_name="cartoons/post.html"))),
Here, If my guess is correct, you are trying to pass id of post model from url to view. But to make ListView accept url kwargs (post_id) you have to write another view in views.py. Maybe something like below.
class EpisodeListView(ListView):
template_name = 'cartoons/post.html'
def get_queryset(self):
return post_episode.objects.filter(post_id=self.kwargs['post_id']).order_by("-date")
Then route a url to that view:
from <yourapp.views> import EpisodeListView
from django.contrib.auth.decorators import login_required
url(r'^episodes/(?P<pk>\d+)$',login_required(EpisodeListView.as_view())
views.py
from django.shortcuts import render_to_response
from models import Post
def getRecentPosts(request):
posts = Post.objects.all()
# sort by chronological order
sorted_posts = posts.order_by('-pub_date')
# display all posts
return render_to_response('posts.html', {'posts': sorted_posts})
posts.html
<html>
<head>
<title>My Django Blog</title>
</head>
<body>
{% for post in posts %}
<h1>{{post.title}}</h1>
<h3>{{post.pub_date}}</h3>
{{ post.text }}
{% endfor %}
</body>
This code works fine & prints the proper data.... However if i change
return render_to_response('posts.html', {'posts': sorted_posts})
to
return render_to_response('posts.html', {'po': sorted_posts})
and
{% for post in posts %} to {% for post in po %}
in posts.html
It fails to generate any data..... So what is the relation between the dictionary name in view and template