I built a small Django Blog application with a comment section. Users are required to login before making a post or comment. I want to return the full name of my CustomUser in both the Blog posts and comments in my templates. After a Blog post, the full name returns as expected, but the author of the comment returns the value of the username field of my CustomUser model i.e None. Please help. Here is my code.
CustomUser model
from django.contrib.auth.models import AbstractUser
from django.db import models
from . manager import CustomUserManager
class CustomUser(AbstractUser):
email = models.EmailField(verbose_name = 'email address', unique=True)
username = None
first_name = models.CharField(verbose_name = 'first_name', blank = True, max_length = 30)
last_name = models.CharField(verbose_name = 'last_name', blank = True, max_length = 30)
bio = models.CharField(max_length = 150, null = True, blank = True)
avatar = models.ImageField(upload_to = 'avatars', null = True, blank = True)
date_joined = models.DateTimeField(auto_now_add = True)
last_login = models.DateTimeField(auto_now_add = True)
def __str__(self):
return self.first_name + " " + self.last_name
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
Blog model
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length = 200, unique = True)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name = 'blog_posts',
)
post_picture = models.ImageField(upload_to = 'post_picture', null = True, blank = True)
approved_comment = models.BooleanField(default=True)
def approve(self):
self.approved_comment = True
self.save()
class Meta:
ordering = ['created_on']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
def approved_comments(self):
return self.comments.filter(approved_comment = True)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name = 'blog_comments',
null = True,
)
text = models.CharField(max_length = 300,)
created_date = models.DateTimeField(auto_now_add = True)
approved_comment = models.BooleanField(default=True)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
View
from django.views.generic import ListView, DetailView, CreateView
from django.views.generic.edit import UpdateView, DeleteView, FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from . models import Post, Comment
from .forms import PostForm, CommentForm
from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.decorators import login_required
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'post_new.html'
fields = ['title', 'body',]
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
def get_queryset(self):
return Post.objects.order_by('created_on').reverse()
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'body', ]
template_name = 'post_edit.html'
login_url = 'login'
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
template_name = 'post_delete.html'
success_url = reverse_lazy('post_list')
login_url = 'login'
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'add_comment_to_post.html', {'form': form})
@login_required
def comment_approve(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.approve()
return redirect('post_detail', pk=comment.post.pk)
@login_required
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.delete()
return redirect('post_detail', pk=comment.post.pk)
Template
{% extends 'blog_template.html' %}
{% load static %}
{% load widget_tweaks %}
{% block blog_center %}
<div class="post-entry">
<h2>{{ object.title }}</h2>
<p>by {{ object.author }} | {{ object.date }}</p>
<p>{{ object.body }}</p>
</div>
<p>Back to <a href="{% url 'post_list' %}">All Posts</a>.</p>
{% if user.is_authenticated %}
<a class="" href="{% url 'add_comment_to_post' pk=post.pk %}">Add comment</a>
{% else %}
<a href="{% url 'login' %}">Log In</a>
{% endif %}
{% for comment in post.comments.all %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="">
<div class="">
{{ comment.created_date }}
{% if not comment.approved_comment %}
<a class="btn btn-default" href="{% url 'comment_remove' pk=comment.pk %}"><span class="glyphicon glyphicon-remove"></span></a>
<a class="btn btn-default" href="{% url 'comment_approve' pk=comment.pk %}"><span class="glyphicon glyphicon-ok"></span></a>
{% endif %}
</div>
<p>{{ comment.author }}</p>
<p>{{ comment.text|linebreaks }}</p>
</div>
{% endif %}
{% empty %}
<p>No comments here yet :</p>
{% endfor %}
{% endblock blog_center %}