0

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 %}

1 Answers1

0

I could't figure out what was causing it, but i implemented another way, which worked.

I first created a CharField in my comment model.

Then i assigned request.user to that field in my views, upon validation of the form. I then saved it to the database.

Then i returned the value in my template. Here is my updated code.

models.py

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'
                                )
    comment_author          = models.CharField(max_length = 200, 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

views.py

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.comment_author = request.user
            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.created_on }}</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>
                {{ comment.comment_author }} 
                {{ comment.text|linebreaks }}
            </div>
        {% endif %}       
    {% empty %}
            <p>No comments here yet :</p>
    {% endfor %}
{% endblock blog_center %}