I have a login system where you need to be logged in to submit a new post. My "New Post" page/form work fine and the content the user submits is properly posted in the database, how when it comes to displaying that content on the home page only the title and subtitle are shown (which are Charfields) and no the body text of the post (which is a text field).
inde.html
{% extends "blog/base.html" %}
{% block body_block %}
<div class="left">
{% if userposts %}
{% for posts in userposts %}
<div class="front-post">
<h2 class="post-title">{{ posts.post_title }}</h2>
<h3 class="post-sub-title">{{ posts.post_sub_title }}</h3>
<p class="post-author">{{ post.post_author }}</p>
<p class="post-date">{{ post.post_date }}</p>
<p class="post-body">{{ post.post_body }}</p>
</div>
{% endfor %}
{% endif %}
</div>
<div class="right">
<p>SIDE BAR</p>
</div>
{% endblock %}
views.py
from django.shortcuts import render
from blog.forms import UserForm,UserProfileInfoForm,AddPost
from blog.models import UserPosts
from django.contrib.auth import authenticate,login,logout
from django.http import HttpResponseRedirect,HttpResponse
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
# Create your views here.
def index(request):
post_list = UserPosts.objects.order_by('post_date')
post_dict = {'userposts':post_list}
return render(request, 'blog/index.html',context=post_dict)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfileInfo(models.Model):
user = models.OneToOneField(User)
portfolio_site = models.URLField(blank=True)
profile_pic = models.ImageField(upload_to='profile_pics',blank='True')
def __str__(self):
return self.user.username
class UserPosts(models.Model):
post_title = models.CharField(max_length=100,unique=True)
post_sub_title = models.CharField(max_length=250,unique=False)
post_author = ''
post_date = models.DateField(auto_now=True)
post_body = models.TextField(max_length=1000,unique=False)
def __str__(self):
return str(self.post_title)
forms.py
from django import forms
from django.contrib.auth.models import User
from blog.models import UserProfileInfo,UserPosts
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username','email','password')
class UserProfileInfoForm(forms.ModelForm):
class Meta():
model = UserProfileInfo
fields = ('portfolio_site','profile_pic')
class AddPost(forms.ModelForm):
class Meta():
model = UserPosts
fields = '__all__'
Watch your naming. Your for loop variable is named posts (with an s at the end) but you're trying to display post.post_body. In some places it's working because you're using posts.post_title.
To fix this issue, rename posts to just post everywhere in your for loop.
{% for post in userposts %}
<div class="front-post">
<h2 class="post-title">{{ post.post_title }}</h2>
<h3 class="post-sub-title">{{ post.post_sub_title }}</h3>
<p class="post-author">{{ post.post_author }}</p>
<p class="post-date">{{ post.post_date }}</p>
<p class="post-body">{{ post.post_body }}</p>
</div>
{% endfor %}
Django will silently fail any expressions it can't evaluate in the templates, which is why nothing was being shown.
Related
First of all sorry for my bad english but i'm french.
I am currently working on a django app and i'm trying to make my HTML page work but it won't and i dont know why.
I followed the tutoriel but i edited some of the code to fit my purpose. And now my page won't print out my variable.
I have python 2.7.5 and Django 1.11.29
My html page
Now this is my code for the HTML :
{% if True %}
<p> Vrai </p>
<li>{{ Thriller.title }}</li>
{% else %}
<p> faux </p>
{% endif %}
<ul>
<p> Paragraphe : </p>
<li>{{ Thriller.title }}</li>
<li>{{ Thriller.id }}</li>
</ul>
My code for the Django part :
This is in the models.py file :
from django.db import models
import datetime
from django.utils.encoding import python_2_unicode_compatible
from django.utils import timezone
class Artist(models.Model):
name = models.CharField(max_length=200, unique=True)
def __str__(self):
return self.name
class Album(models.Model):
reference = models.IntegerField(null=True)
created_at = models.DateTimeField(auto_now_add=True)
available = models.BooleanField(default=True)
title = models.CharField(max_length=200, unique=True)
picture = models.URLField()
artists = models.ManyToManyField(Artist, related_name='albums', blank=True)
def __str__(self):
return self.title
This is in the views.py file :
from __future__ import unicode_literals
from django.shortcuts import render
from django.http import HttpResponse
from .models import Album, Artist, Contact, Booking
from django.template import loader
def index(request):
albums = Album.objects.order_by('-created_at')
context = {'albums = ': albums}
template = loader.get_template('polls/index.html')
return HttpResponse(template.render(context, request))
This is also my first post here and i dont really know if the post is good or not so forgive it if it's not good !
You can ask me anything you want. Thank's !
You need to call your context variable in the template instead of {{ Thriller.title }} because you did not specify Thriller in the context of your view.
Your context in the index() view:
context = {'albums = ': albums}
Edit this to:
context = {'albums': albums}
and then in your template, for example to loop over all the album titles:
added the if statement:
{% for album in albums %}
{% if album.title == "Thriller" %}
<p>{{ album.title }}</p>
{% endif %}
{% endfor %}
Try this change to your context
context = {'albums': albums}
Then in your template do...
{% for album in albums %}
<p>{{ album.title }}</p>
{% endfor %}
I made a notification system. When "B" user comments at "A" user's post, notification sends to A.
This is my part of my code.
models.py
from django.db import models
from freeboard.models import FreeBoardComment
from users.models import CustomUser
class Notification(models.Model):
TYPE_CHOCIES = (
("FreeBoardComment", "FreeBoardComment"),
)
creator = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, related_name="creator")
to = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, related_name="to")
notification_type = models.CharField(max_length=50, choices=TYPE_CHOCIES)
comment = models.CharField(max_length=1000, blank=True, null=True)
post_id = models.IntegerField(null=True)
class Meta:
ordering = ["-pk"]
def __str__(self):
return "From: {} - To: {}".format(self.creator, self.to)
notification/views.py
from django.views.generic import ListView
from .models import Notification
def create_notification(creator, to, notification_type, comment, post_id):
if creator.email != to.email:
notification = Notification.objects.create(
creator=creator,
to=to,
notification_type=notification_type,
comment=comment,
post_id=post_id,
)
notification.save()
class NotificationView(ListView):
model = Notification
template_name = "notification/notification.html"
freeboard/views.py
...
#login_required
def comment_write(request, pk):
post = get_object_or_404(FreeBoardPost, pk=pk)
if request.method == 'POST':
form = CreateFreeBoardComment(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.comment_writer = request.user
comment.post = post
comment.save()
# 포인트
award_points(request.user, 1)
### NOTIFICATION PART!!!! ###
create_notification(request.user, post.author, "FreeBoardComment", comment.comment_text, post.pk)
### NOTIFICATION PART !!! ###
return redirect("freeboard_detail", pk=post.id)
else:
form = CreateFreeBoardComment()
return render(request, "bbs/freeboard/free_board_comment.html", {"form": form})
notification.html
{% extends "base.html" %}
{% block css_file %}
<link href="/static/css/notification/notification.css" rel="stylesheet">
{% endblock %}
{% block content %}
<ul class="list-group">
{% for notification in notification_list %}
<li class="list-group-item dropdown">
<a href="{% if notification.notification_type == "FreeBoardComment" %}/free/{{ notification.post_id }}{% endif %}"
class="dropdown-toggle" style="color: #555; text-decoration: none;">
<div class="media">
<img src="{{ notification.creator.image.url }}" width="50" height="50"
class="pull-left img-rounded" style="margin: 2px"/>
<div class="media-body">
<h4 class="media-heading"><span
class="genre">[#{{ notification.to.nickname }}]</span> {{ notification.comment }}
</h4>
<span style="font-size: 0.9rem;"><i
class="fa fa-user"></i> {{ notification.creator.nickname }}</span>
</div>
</div>
</a>
</li>
{% endfor %}
</ul>
{% endblock %}
And what I'm trying to add is notification delete feature WITHOUT TEMPLATE(deleteview).
When user clicked the notification and redirected to url, I want to delete that notification.
Is there way I can do this?
you code is a little bit confusing but i here is the thing, i think it would be better to use DRF and remove the notification without the redirection like #Edgardo_Obregón mentioned. or if you don't wanna use DRF, then it would be a good idea if you simply use a small view:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt # if you wanna bypass csrf, otherwise you can use csrf with ajax docs
def delete_notification(request,pk):
if request.METHOD == "DELETE": # optional
notification = Notification.objects.get(pk=pk)
if notification is not None:
notification.delete()
csrf with ajax docs
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 have a system setup to show comments on a post detail page, however the comments are not showing. I have been focusing on the template tags, because I have used this view code elsewhere and it has worked, however I may be wrong. No errors returning, just not showing the comment in the detail view.
userpost_detail.html:
{% extends 'base.html' %}
{% block content %}
<div class="main">
<h1 class="posttitle">{{ userpost.title }}</h1>
<p class="postcontent">{{ userpost.post_body }}</p>
{% if request.user.is_authenticated and request.user == post.author %}
<a class="link" href="{% url 'feed:edit_post' post.id %}">Edit Post</a>
{% endif %}
Add Comment
{% for comment in userpost.usercomment.all %}
{% if user.is_authenticated %}
{{ comment.create_date }}
<!--
<a class="btn btn-warning" href="{% url 'comment_remove' pk=comment.pk %}">
<span class="glyphicon glyphicon-remove"></span>
</a>
-->
<p>{{ comment.comment_body }}</p>
<p>Posted By: {{ comment.author }}</p>
{% endif %}
{% empty %}
<p>No Comments</p>
{% endfor %}
</div>
{% include 'feed/sidebar.html' %}
{% endblock %}
app PostDetailView:
class PostDetailView(DetailView):
model = UserPost
app add_comment_to_post view:
#login_required
def add_comment_to_post(request,pk):
post = get_object_or_404(UserPost,pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.author = request.user
comment.save()
return redirect('feed:post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request,'feed/comment_form.html',{'form':form})
app urls:
from django.conf.urls import url
from feed import views
app_name = 'feed'
urlpatterns = [
url(r'^new/$',views.CreatePostView.as_view(),name='new_post'),
url(r'^post/(?P<pk>\d+)$',views.PostDetailView.as_view(),name='post_detail'),
url(r'^post/(?P<pk>\d+)/edit/$',views.UpdatePostView.as_view(),name='edit_post'),
url(r'^post/(?P<pk>\d+)/delete/$',views.DeletePostView.as_view(),name='delete_post'),
url(r'^post/(?P<pk>\d+)/comment/$',views.add_comment_to_post,name='add_comment'),
]
Models.py:
from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from django.contrib.auth import get_user_model
User = get_user_model()
# Create your models here.
class UserPost(models.Model):
author = models.ForeignKey(User,related_name='userpost',null=True)
post_date = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=150,blank=False)
post_body = models.TextField(max_length=1000,blank=False)
def publish(self):
self.save()
def get_absolute_url(self):
return reverse('index')
def __str__(self):
return self.title
class UserComment(models.Model):
post = models.ForeignKey('feed.UserPost',related_name='comments')
author = models.ForeignKey(User,related_name='usercomment')
comment_date = models.DateTimeField(auto_now_add=True)
comment_body = models.TextField(max_length=500)
def publish(self):
self.save()
def get_absolute_url(self):
return reverse("userpost_list")
def __str__(self):
return self.comment_body
As #user6731765 mentioned you need comments coz of related_name
{% for comment in userpost.comments.all %}
When you get comment_remove error
You need to define a url for comment_remove and define a view for that.
urlpatterns = [
. . . . . .
url(r'^comment/remove/(?P<pk>\d+)/$',views.DeleteCommentView.as_view(),name='comment_remove'),
]
Then in views.py
class DeleteCommentView(DeleteView):
model=UserComment
Due to the related_name you are using for posts in UserComment, try using
{% for comment in userpost.comments.all %}
in your template instead.
Hi everybody!
Im just starting a way of django programming so sometimes really get confused.
I`m trying to display all my objects from DB, but when opening the page its simply empty.
There are content added and I tried ListView previously and it worked for me. But now I need to dislpay objects like a grid and here is an issue with this method.
Will be very thanksfull for any help!
models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=140)
body = models.TextField()
date = models.DateField()
image = models.ImageField(upload_to='bons_images/%Y/%m/%d')
def __str__(self):
return self.title
views.py
from django.shortcuts import render, render_to_response
from django.template import RequestContext
from django.views import generic
from blog.models import Post
def image(request):
post = Post()
variables = RequestContext(request, {
'post': post
})
return render_to_response('blog/post.html', variables)
# class IndexView(generic.ListView):
# template_name = 'blog/blog.html'
# context_object_name = 'all_posts'
#
# def get_queryset(self):
# return Post.objects.all()
def index(request):
posts = Post.objects.all()
return render(request, 'blog/blog.html', {'posts': posts})
urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from blog.models import Post
from blog import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<pk>\d+)$', DetailView.as_view(model=Post, template_name='blog/post.html')),
]
blog.html
{% extends 'base.html' %}
{% block content %}
{% if all_posts %}
{% for post in all_posts %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-lg-4">
<div class="thumbnail">
<a href="/blog/{{ post.id }}">
<h5>{{ post.date|date:'Y-m-d' }} {{ post.title }}</h5>
<img src="{{ post.image.url }}" style="width: 50%; height: 50%"/>
</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
{% endblock %}
And by the way, how its possible to display your objects like in grid, not list, using Bootstrap or so on.
Thank you!
You're iterating over something called all_posts in your template. But your view doesn't send anything called all_posts; it only sends posts. You need to use consistent names.