Lesson 3: Forms – The Art of Asking Nicely for User Input (Without Scaring Them Away)


Lesson 3

Lesson 3: Forms – The Art of Asking Nicely for User Input (Without Scaring Them Away)

Hello again, brave adventurer! 🧙‍♂️ By now, you’ve created models, set up URLs, and displayed your blog posts like a pro. But what’s the fun in a blog if your visitors can’t interact with you (or more specifically, send you random comments about your choice of font)? This brings us to today’s magical spell: forms.

Forms are the gateway to user interaction. They’re how you get valuable input from users—whether it’s comments, feedback, or, let’s face it, spam (we’ll protect against that too). In this lesson, we’re going to create a comment form for your blog. So buckle up—it’s going to be fun!


Step 1: Activate the Virtual Environment (Your Protective Bubble)

Before doing anything, make sure you’re inside your virtual environment. This environment is like your magical bubble where all your dependencies live in harmony.

If your virtual environment isn’t already active, run the following command:

source venv/bin/activate

If you’re on Arch Linux, make sure you have the virtual environment set up using this command:

sudo pacman -S python-virtualenv

Once you’re in the virtual environment, you’ll know you’re there when you see (venv) at the start of your terminal prompt. Now you’re in your cozy, magical coding space.


Step 2: Create the BlogPost Model (Our Magic Spellbook)

Before we dive into comments, remember that we’re building comments for blog posts. That means we need the BlogPost model as the base of our blog. Let’s ensure we have the BlogPost model set up in models.py like this:

from django.db import models

class BlogPost(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return self.title

Step 3: Create the Comment Model (Because Data Needs a Home)

Now that we have the BlogPost model, we need to create a model to store comments, because every post needs a little feedback (or snark). Below the BlogPost model in models.py, add the Comment model like this:

class Comment(models.Model):
    blog_post = models.ForeignKey(BlogPost, on_delete=models.CASCADE, related_name='comments')
    author = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'Comment by {self.author} on {self.blog_post}'

Step 4: Create and Apply Migrations (Again, Because Databases Need Love Too)

Just like we did with blog posts, we need to let the database know about our shiny new Comment model. Run the following commands:

python3 manage.py makemigrations
python3 manage.py migrate

Boom! The Comment table now exists, ready to hold all the feedback (or snark) your readers will send your way.


Step 5: Create the CommentForm (Asking Nicely for Input)

Next, we need to create a form so users can submit their comments. Django makes forms easy—like, really easy.

Create a new file in your blog directory called forms.py and add this code:

from django import forms
from .models import Comment

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['author', 'content']

Django’s ModelForm is like a magical spell that automatically creates a form based on your model. It’s almost like cheating, but don’t worry, it’s totally legal.


Step 6: Handle the Form in the View (Where the Magic Happens)

Now that we have a form, we need to display it and handle the user’s input when they submit it. Let’s modify our blog_index view in views.py to include this new feature.

Also, make sure you import the get_object_or_404 function from Django’s shortcuts module to avoid errors when retrieving individual blog posts.

Here’s the corrected views.py:

from django.shortcuts import render, get_object_or_404, redirect  # Make sure this line includes get_object_or_404
from .models import BlogPost, Comment
from .forms import CommentForm

def blog_index(request):
    posts = BlogPost.objects.all().order_by('-created_at')
    return render(request, 'blog_index.html', {'posts': posts})

def blog_post_detail(request, pk):
    post = get_object_or_404(BlogPost, pk=pk)  # Corrected import for get_object_or_404
    comments = post.comments.all()

    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.blog_post = post
            comment.save()
            return redirect('blog_post_detail', pk=post.pk)
    else:
        form = CommentForm()

    return render(request, 'blog_post_detail.html', {'post': post, 'comments': comments, 'form': form})

Step 7: Create the Template to Display the Form (Let the Users Speak!)

Now, let’s modify the template so users can see the form and leave comments on your blog posts. Open or create a file called blog_post_detail.html in the templates directory and add the following:

<!DOCTYPE html>
<html>
<head>
    <title>{{ post.title }}</title>
</head>
<body>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>

    <h2>Comments</h2>
    <ul>
        {% for comment in comments %}
        <li><strong>{{ comment.author }}</strong>: {{ comment.content }}</li>
        {% endfor %}
    </ul>

    <h3>Leave a Comment</h3>
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Submit</button>
    </form>
</body>
</html>

Step 8: Add a URL for the Blog Post Detail View

Finally, let’s set up a URL so users can visit the detailed view of each blog post. Open urls.py in your blog app and add this line:

from . import views

urlpatterns = [
    path('', views.blog_index, name='blog_index'),
    path('post/<int:pk>/', views.blog_post_detail, name='blog_post_detail'),
]

This route maps URLs like /post/1/ to the blog post with the corresponding ID (in this case, post #1). Visitors can now view the full post and its comments.

You can test this by visiting http://127.0.0.1:8000/blog/post/1/ after creating your first blog post.


Step 9: Deactivate the Virtual Environment

Once you’ve finished your work for the day (or just need a snack break), don’t forget to deactivate your virtual environment to exit your cozy coding bubble.

Simply run:

deactivate

Your terminal should no longer show (venv) at the beginning of the prompt, meaning you’re back to your normal system environment.


Conclusion of Lesson 3

Congratulations, brave wizard! 🎉 You’ve successfully integrated forms into your Django blog. Now, your visitors can leave comments on your posts—whether they’re insightful critiques or just “Nice post!” or even “You misspelled something” (hey, it happens).

In the next lesson, we’ll dive into user authentication—because not everyone should be allowed to comment willy-nilly, right? Until then, enjoy your new interactive blog and maybe go moderate those comments (before the trolls arrive).


See also