DEV Community

Jonathan Farinloye
Jonathan Farinloye

Posted on

Models, Views, Templates - Lesson 5

  1. Introduction
  2. Templates to Views to Models
  3. Displaying From Models

Introduction

In the last article, we discussed how we can create a blog model in our blog app. This model contained a title, a cover image, a date field, a content field, and a slug field. Out of all these fields, we would be working on and interacting with the title, cover image and content fields. We would also be setting the date field to be automatically set to the date of the last update to our blog post, and the slug to be automatically set based on the title. I think that's a nice place to start. 🤔

Move over to your blog/models.py file and edit the field called raw_date. Also add the save function to the class.

# blog/models py
from django.template.defaultfilters import slugify # a django module to take care of creating slugs
class Blog(models.Model):
...
    raw_date = models.DateTimeField(auto_now=True)
...
    def save(self, *args, **kwargs):
        self.slug = slugify(self.title)
        return super(Blog, self).save(*args, **kwargs)
...

The parameter auto_now, when set to True, automatically sets the date to the latest date every time the model is edited and saved.
Note also, the function we added must be named save for this to work, because it, for lack of the right word, extends the original inbuilt save function.

Do not forget to makemigrations and migrate your changes. Feel free to also test it to make sure it works. If you check the admin site, you would not find the date field anymore. This is because it is being automatically set.

Date field seems to have disappeared
Date was eaten by a hungry squirrel 🐿️

Templates to Views to Models

Don't get confused by the long heading. It's not that serious really 😉. Or is it 🤔? Just kidding. On a more serious note though, our main goal is to allow blog posts to be created from the frontend and to do this, we basically need just a form that has the fields of the model we created, with an exception of the automatically populated fields (I was going to say filled fields). So we need to create an HTML file that would hold the form (We really aren't bothering about the styling now. Feel free, though, to style however you want).

Move over to your blog app and create a templates directory if you don't already have one. Next, create a file, I'd name mine add-blog. So, blog/templates/add-blog.html. Let's move over to our views.py and create the function for our add a blog page.

...
# blog/views.py
from django.shortcuts import render, redirect
...
def add_blog_post(request):
    return render(request, 'add-blog.html')

For now, we'd just return the html document

We need to create a urls.py file inside the blog app and link the file to the main urls.py inside the awesome directory.

# blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('add-post/', views.add_blog_post, name='add-a-post')
 ]

In awesome/urls.py

# awesome/urls.py
...
from django.urls import path, include
...
    path('counts/', views.counter, name='count-vowels'), # Don't forget this comma
    path('blog/', include('blog.urls'))
...

The new line includes the blog/urls.py file in the recognized urls.

Now, go back to your html file and create the form.

<!-- blog/templates/add-blog.html -->
...
<form action="{% url 'add-a-post' %}" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <label for="title-field">Title</label>
    <input id="title-field" name="title" type="text">
    <br><br>
    <label for="cover">Cover Image</label>
    <input id="cover" name="cover-image" type="file">
    <br><br>
    <label for="blog-content">Content</label>
    <textarea id="blog-content" rows="20" cols="30" name="content"></textarea>
    <br><br>
    <input type="submit" value="Post">
</form>
...

Don't forget to include your csrf_token, else it won't work

Image showing how form looks
Please style if you can. This thing is ugly.

Now, go to blog/views.py and let's make changes to the function.

# blog/views,py
...
from .models import Blog
...
def add_blog_post(request):
    if request.method == 'POST':
        blog = Blog()
        blog.title = request.POST['title']
        blog.cover = request.FILES['cover-image']
        blog.content = request.POST['content']
        blog.save()
        return redirect('home')
    return render(request, 'add-blog.html')

Note: This fetches the information from the name given to each of the fields, meaning if you don't give it a name, accessing the information might be difficult.

When we run blog.save(), a blog post is created with the given information. Save your code, and test it. Login to the admin site and confirm that it saves.

Image showing newly created blog post

Image showing newly created blog post on the admin site

Displaying from Models

Currently when a blog post is created, we redirect the user to the home page. Not so ideal. We would want to redirect the user, however, to a page that lists all out posts. To do this, we need a page, a function and a new url entry.

blog/views.py

# blog/views.py
...
def all_posts(requests):
    posts = Blog.objects.all()
    return render(requests, {'all-posts': posts})
...

blog/templates/all-posts.html

<!-- blog/templates/all-posts.html -->
...
<body>
{% for post in all %}
    <h3>{{ post.title }}</h3>
    {{ post.date }}
    <br>
    {{ post.content }}
    <hr>
{% endfor %}
</body>
...

blog/urls.py

# blog/urls.py
...
urlpatterns = [
    path('add-post/', views.add_blog_post, name='add-a-post'),
    path('all-posts', views.all_posts, name='all-posts')
 ]
...

This are all the changes made and their respective files. And just like this, we are able to access and display our blog posts on the frontend.

I'd want you to, in your own free time, extend the blog model. Try adding categories using the ManytoMany field. We'd be extending the model and possibly dealing with user accounts soon.

One thing to note is, there are other ways to handle forms in Django. This is one, and not the only way. Feel free to check around for other methods and possibly try them too. 🦉. Stay safe. Be nice. Enjoy your day.

Latest comments (0)