<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: faozziyyah</title>
    <description>The latest articles on DEV Community by faozziyyah (@faozziyyah).</description>
    <link>https://dev.to/faozziyyah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F435412%2F6e628cb6-3dfd-460b-8c33-eed8f41eea81.jpg</url>
      <title>DEV Community: faozziyyah</title>
      <link>https://dev.to/faozziyyah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/faozziyyah"/>
    <language>en</language>
    <item>
      <title>Blog App with Django and Bulma CSS Framework</title>
      <dc:creator>faozziyyah</dc:creator>
      <pubDate>Wed, 25 Jan 2023 13:22:56 +0000</pubDate>
      <link>https://dev.to/faozziyyah/blog-app-with-django-and-bulma-css-framework-21ah</link>
      <guid>https://dev.to/faozziyyah/blog-app-with-django-and-bulma-css-framework-21ah</guid>
      <description>&lt;p&gt;Previously, I've built a blog app with Flask, you can check out my article on it &lt;a href="https://dev.to/faozziyyah/how-to-build-a-blog-app-with-flask-9h2"&gt;here&lt;/a&gt;. Then, I decided to build another one using Django and another CSS framework called Bulma. This time around, I added additional features to my blog post such as categories, post approval by admin, like and unlike post, follow and unfollow users, profile and account settings.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain how to build this blog app with Django and Bulma CSS for styling.&lt;br&gt;
Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. You can learn more about it by &lt;a href="https://www.djangoproject.com/" rel="noopener noreferrer"&gt;visiting this website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article is divided into four parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login, Logout, Signup, Profile and Account Settings&lt;/li&gt;
&lt;li&gt;Add post, view all post, edit post, delete and view individual post.&lt;/li&gt;
&lt;li&gt;Like and unlike post, add comments and view post categories.&lt;/li&gt;
&lt;li&gt;Admin page, view other users, follow and unfollow users.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;p&gt;The following are the basic requirements before starting this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;Git bash&lt;/a&gt; or any other terminal&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bulma.io/documentation/" rel="noopener noreferrer"&gt;Bulma&lt;/a&gt; - CSS framework for styling our application&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. Setting Up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A. Create a Project folder:&lt;/strong&gt; navigate into the section where you want to have your project and type these commands to create a new directory or folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// create a new directory(folder)
$ mkdir blog-app

// navigate into the folder
$ cd blog-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B. Create a virtual environment:&lt;/strong&gt; &lt;a href="https://www.geeksforgeeks.org/python-virtual-environment/" rel="noopener noreferrer"&gt;virtual environment&lt;/a&gt; is a tool that helps to keep dependencies required by different projects separate by creating isolated python virtual environments for them. This is one of the most important tools that most Python developers use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// navigate into the folder
$ cd blog-app

// create a virtual environment
$ python3 -m venv venv

// activate the virtual environment
$ . venv/Scripts/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C. Install Django&lt;/strong&gt;: &lt;code&gt;pip install django&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;D. Start your Project&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ django-admin startproject edublog

$ cd edublog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;E. Create App&lt;/strong&gt;: &lt;code&gt;python manage.py startproject blog&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;F. Add app to settings.py:&lt;/strong&gt; open up the settings.py file in your edublog folder and add the new app to INSTALLED_APPS within settings.py.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjjj7buo0mie7pe1y6k7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjjj7buo0mie7pe1y6k7.png" alt="Image description" width="705" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;G. create other folders:&lt;/strong&gt; Create TEMPLATES folder for our HTML files, MEDIA folder for uploading images and STATIC folder for images and CSS files.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6iw3orbbi9y1yjupx3dq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6iw3orbbi9y1yjupx3dq.png" alt="Image description" width="217" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;H. STATICFILES_DIRS:&lt;/strong&gt; add STATICFILES_DIRS to the settings.py file in order to see the effect of the styles similarly for the images.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyswstais51xd8xry1us.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyswstais51xd8xry1us.png" alt="Image description" width="755" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I. Further Set-up:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejvjxbskvm4qsu7zqpzc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fejvjxbskvm4qsu7zqpzc.png" alt="Adding templates directory to settings.py" width="793" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8gf0vwq14kn7bp63pzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8gf0vwq14kn7bp63pzp.png" alt="urls.py" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;J. Adding broiler plates to HTML:&lt;/strong&gt; add these to your base.html and index.html files. This includes the set up for the bulma CSS framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;

    &amp;lt;link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"&amp;gt;
    {% load static %}
    &amp;lt;link rel="stylesheet" href="{% static 'css/bulma.min.css' %}"&amp;gt;
    &amp;lt;script src="https://kit.fontawesome.com/1cbee15c00.js" crossorigin="anonymous"&amp;gt;&amp;lt;/script&amp;gt;

    &amp;lt;title&amp;gt;Edublog&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;footer class="columns" id="footer"&amp;gt;

        &amp;lt;div class="column"&amp;gt;
            &amp;lt;h5&amp;gt;Links&amp;lt;/h5&amp;gt;
                &amp;lt;a href="{% url 'index' %}"&amp;gt;Home&amp;lt;/a&amp;gt;
                &amp;lt;a href="{% url 'about' %}"&amp;gt;About&amp;lt;/a&amp;gt;
                &amp;lt;a href="{% url 'about' %}"&amp;gt;Contact&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class="column"&amp;gt;

            &amp;lt;a class="button is-success" href="http://www.facebook.com/profile.php?id="&amp;gt;&amp;lt;i class="fab fa-facebook"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;
            &amp;lt;a class="button is-primary" href="http://www.linkedin.com/in/"&amp;gt;&amp;lt;i class="fab fa-linkedin"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;
            &amp;lt;a class="button is-link" href="http://twitter.com/"&amp;gt;&amp;lt;i class="fab fa-twitter"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;
            &amp;lt;a class="button is-danger" href="http://youtube.com/"&amp;gt;&amp;lt;i class="fab fa-youtube"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;
            &amp;lt;a class="button is-warning" href="mailto:"&amp;gt;&amp;lt;i class="fas fa-envelope"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/a&amp;gt;

        &amp;lt;/div&amp;gt;

        &amp;lt;div class="column"&amp;gt;
            &amp;lt;p&amp;gt;© All rights reserved {{ current_year }} Faozziyyah Daud&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;

  &amp;lt;/footer&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;K. Navbar setup:&lt;/strong&gt; add the following Bulma CSS navbar element to both base and index html files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;header&amp;gt;
        &amp;lt;!-- Fixed navbar --&amp;gt;
        &amp;lt;nav class="navbar is-link" role="navigation" aria-label="main navigation"&amp;gt;

            &amp;lt;div class="navbar-brand"&amp;gt;
                &amp;lt;a class="navbar-item" href="{% url 'index' %}"&amp;gt;
                    &amp;lt;img src="{% static 'images/logo.png' %}" width="" height=""&amp;gt;
                &amp;lt;/a&amp;gt;

                &amp;lt;a role="button" class="navbar-burger is-active" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"&amp;gt;
                  &amp;lt;span aria-hidden="true"&amp;gt;&amp;lt;/span&amp;gt;
                  &amp;lt;span aria-hidden="true"&amp;gt;&amp;lt;/span&amp;gt;
                  &amp;lt;span aria-hidden="true"&amp;gt;&amp;lt;/span&amp;gt;
                &amp;lt;/a&amp;gt;
            &amp;lt;/div&amp;gt;

            &amp;lt;div id="navbarBasicExample" class="navbar-menu is-active"&amp;gt;

                &amp;lt;div class="navbar-start"&amp;gt;

                    &amp;lt;div class="navbar-item"&amp;gt;
                        &amp;lt;a href="{% url 'index' %}" class="nava"&amp;gt;&amp;lt;i class="fas fa-home"&amp;gt;&amp;lt;/i&amp;gt; Home &amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="navbar-item"&amp;gt;
                        &amp;lt;a href="{% url 'add-post' %}" class="nava"&amp;gt;&amp;lt;i class="fa fa-plus-circle" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt; Add Post &amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="navbar-item has-dropdown is-hoverable"&amp;gt;    
                        &amp;lt;a class="navbar-link"&amp;gt;&amp;lt;i class="fa fa-info-circle" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt; More &amp;lt;/a&amp;gt;

                        &amp;lt;div class="navbar-dropdown"&amp;gt;    
                            &amp;lt;a class="navbar-item" href="{% url 'about' %}"&amp;gt;&amp;lt;i class="fa fa-info-circle" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt; About &amp;lt;/a&amp;gt;
                            &amp;lt;a href="{% url 'about' %}" class="navbar-item"&amp;gt; &amp;lt;i class="fa fa-address-card"&amp;gt;&amp;lt;/i&amp;gt; Contact &amp;lt;/a&amp;gt;    
                            &amp;lt;hr class="navbar-divider"&amp;gt;    
                            &amp;lt;a class="navbar-item"&amp;gt; Report an issue &amp;lt;/a&amp;gt;
                        &amp;lt;/div&amp;gt;

                    &amp;lt;/div&amp;gt;

                &amp;lt;/div&amp;gt;

                &amp;lt;div class="navbar-end"&amp;gt; 

                    &amp;lt;form class="navbar-item" method="POST" action="{% url 'search-posts' %}"&amp;gt;
                        {% csrf_token %}

                        &amp;lt;div class="field has-addons"&amp;gt;

                            &amp;lt;div class="control"&amp;gt;
                              &amp;lt;input class="input" type="search" style="background-color: transparent;" placeholder="Search posts..." aria-label="Search" name="searched" /&amp;gt;
                            &amp;lt;/div&amp;gt;

                            &amp;lt;div class="control"&amp;gt;
                              &amp;lt;button class="button is-primary" type="submit"&amp;gt; Search &amp;lt;/button&amp;gt;
                            &amp;lt;/div&amp;gt;

                        &amp;lt;/div&amp;gt;

                    &amp;lt;/form&amp;gt;

                    &amp;lt;div class="navbar-item"&amp;gt; 

                        &amp;lt;div class="buttons"&amp;gt; 

                            {% if user.is_superuser %}

                                &amp;lt;a class="navbar-item button is-success is-light" href="{% url 'admin-approval' %}"&amp;gt;
                                    &amp;lt;span class="icon"&amp;gt;
                                        &amp;lt;i class="fa fa-user-circle"&amp;gt;&amp;lt;/i&amp;gt;
                                    &amp;lt;/span&amp;gt;
                                    &amp;lt;span&amp;gt;Admin&amp;lt;/span&amp;gt;
                                &amp;lt;/a&amp;gt;

                            {% endif %}

                            {% if user.is_authenticated %}

                                &amp;lt;div class="navbar-item has-dropdown is-hoverable"&amp;gt;    
                                    &amp;lt;a class="navbar-link"&amp;gt;
                                        &amp;lt;img src="{{user_profile.profileimg.url}}" class="header-avatar" style="width: 32px; height: 32px; border-radius: 100%; margin-left: 15px;"&amp;gt;
                                    &amp;lt;/a&amp;gt;

                                    &amp;lt;div class="navbar-dropdown"&amp;gt;

                                        &amp;lt;a class="navbar-item button is-primary is-light" href="{% url 'settings' %}"&amp;gt;
                                            &amp;lt;span class="icon"&amp;gt;
                                                &amp;lt;i class="fa fa-cog" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt;
                                            &amp;lt;/span&amp;gt;
                                            &amp;lt;span&amp;gt;Account settings&amp;lt;/span&amp;gt;
                                        &amp;lt;/a&amp;gt;

                                        &amp;lt;a class="navbar-item button is-link is-light" href="profile/{{user_profile.user}}"&amp;gt;
                                            &amp;lt;span class="icon"&amp;gt;
                                                &amp;lt;i class="fa fa-user-circle"&amp;gt;&amp;lt;/i&amp;gt;
                                            &amp;lt;/span&amp;gt;
                                            &amp;lt;span&amp;gt;Profile&amp;lt;/span&amp;gt;
                                        &amp;lt;/a&amp;gt;

                                        &amp;lt;hr class="navbar-divider"&amp;gt;    

                                        &amp;lt;a class="navbar-item button is-warning is-light" href="{% url 'logout' %}"&amp;gt;
                                            &amp;lt;span class="icon"&amp;gt;
                                                &amp;lt;i class="fa fa-sign-out" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt;
                                            &amp;lt;/span&amp;gt;
                                            &amp;lt;span&amp;gt;Log Out&amp;lt;/span&amp;gt;
                                        &amp;lt;/a&amp;gt; 

                                    &amp;lt;/div&amp;gt;

                                &amp;lt;/div&amp;gt;  

                            {% else %}

                                &amp;lt;a class="navbar-item button is-primary is-light" href="{% url 'register' %}"&amp;gt;
                                    &amp;lt;span class="icon"&amp;gt;
                                        &amp;lt;i class="fa fa-sign-in" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt;
                                    &amp;lt;/span&amp;gt;
                                    &amp;lt;span&amp;gt;Sign up&amp;lt;/span&amp;gt;
                                &amp;lt;/a&amp;gt;

                                &amp;lt;a class="navbar-item button is-light is-light" href="{% url 'login' %}"&amp;gt;
                                    &amp;lt;span class="icon"&amp;gt;
                                        &amp;lt;i class="fa fa-sign-in" aria-hidden="true"&amp;gt;&amp;lt;/i&amp;gt;
                                    &amp;lt;/span&amp;gt;
                                    &amp;lt;span&amp;gt;Log in&amp;lt;/span&amp;gt;
                                &amp;lt;/a&amp;gt; 

                            {% endif %}  

                        &amp;lt;/div&amp;gt;    
                    &amp;lt;/div&amp;gt;

                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/nav&amp;gt;
      &amp;lt;/header&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L. &lt;strong&gt;Jinja template:&lt;/strong&gt;&lt;a href="https://jinja.palletsprojects.com/en/3.1.x/" rel="noopener noreferrer"&gt;jinja&lt;/a&gt; is a fast, expressive, extensible templating engine. Special placeholders in the template allow writing code similar to Python syntax. Then the template is passed data to render the final document.&lt;br&gt;
Add the following to the base and index html files&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd929rzpf6gwu86gv528p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd929rzpf6gwu86gv528p.png" alt="The block content is the area where all contents of the webpage belongs" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Login and Signup
&lt;/h2&gt;

&lt;p&gt;This enables a new user create an account before viewing the post page. create register.html and login.html files in your templates. You can view the source code &lt;a href="https://github.com/faozziyyah/django-blog-app/blob/main/edublog/templates/register.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Then create a view.py file inside the blog folder and add the following. This determines the route of the pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from . import views
urlpatterns = [
    path('', views.signin, name='login'),
    path('index', views.index, name='index'),
    path('signup', views.signup, name='register'),
    path('logout', views.logout, name='logout'),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This third step is to include the functionalities in the view.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def signin(request):

    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']

        user = auth.authenticate(username=username, password=password)

        if user is not None:
            auth.login(request, user)
            return redirect('/index')
        else:
            messages.info(request, 'Credentials Invalid')
            return redirect('login')

    else:
        return render(request, 'login.html')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and for the signup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def signup(request):

    if request.method == 'POST':
        username = request.POST['username']
        email = request.POST['email']
        password = request.POST['password']
        password2 = request.POST['password2']

        if password == password2:
            if User.objects.filter(email=email).exists():
                messages.info(request, 'Email Taken')
                return redirect('register')
            elif User.objects.filter(username=username).exists():
                messages.info(request, 'Username Taken')
                return redirect('register')
            else:
                user = User.objects.create_user(username=username, email=email, password=password)
                user.save()

                #log user in and redirect to settings page
                user_login = auth.authenticate(username=username, password=password)
                auth.login(request, user_login)

                #create a Profile object for the new user
                user_model = User.objects.get(username=username)
                new_profile = Profile.objects.create(user=user_model, id_user=user_model.id)
                new_profile.save()
                return redirect('settings')
        else:
            messages.info(request, 'Password Not Matching')
            return redirect('register')

    else:
        return render(request, 'register.html')

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Logout user
&lt;/h2&gt;

&lt;p&gt;To enable a user logout successfully, add the following to the views.py file. The &lt;code&gt;@login_required(login_url='login_user')&lt;/code&gt; ensures that the user is logged in before he can logout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@login_required(login_url='login_user')
def logout(request):
    auth.logout(request)
    return redirect('/')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. User Profile
&lt;/h2&gt;

&lt;p&gt;This is the user's personal page where he can view all posts he created, number of followers and number of people he is following. It also contains a like to view his account settings.&lt;br&gt;
&lt;strong&gt;First,&lt;/strong&gt; create a profile.html page, check the source code &lt;a href="https://github.com/faozziyyah/django-blog-app/blob/main/edublog/templates/profile.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;strong&gt;Secondly,&lt;/strong&gt; add the following in the urls.py file &lt;code&gt;&lt;br&gt;
    path('profile/&amp;lt;str:pk&amp;gt;', views.profile, name='profile'),&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;&amp;lt;str:pk&amp;gt;&lt;/code&gt; gets the ID of the current user.&lt;br&gt;
&lt;strong&gt;Thidly,&lt;/strong&gt; add this to the views.py file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# profile page
@login_required(login_url='login_user')
def profile(request, pk):
    user_object = User.objects.get(username=pk)
    user_profile = Profile.objects.get(user=user_object)
    user_posts = Post.objects.filter(user=pk)
    user_post_length = len(user_posts)
    context = {
        'user_object': user_object,
        'user_profile': user_profile,
        'user_posts': user_posts,
        'user_post_length': user_post_length,
    }
    return render(request, 'profile.html', context)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lastly,&lt;/strong&gt; let's create the profile model. Add these to the models.py file. It create a profile table in our databse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models
from django.contrib.auth.models import User
import uuid
from datetime import date, datetime

# Create your models here.
class Profile(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    id_user = models.IntegerField()
    bio = models.TextField(blank=True)
    profileimg = models.ImageField(upload_to='profile_images', default='blank-profile-picture.png')
    location = models.CharField(max_length=100, blank=True)

    def __str__(self):
        return self.user.username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Migrations
&lt;/h2&gt;

&lt;p&gt;After adding a table or making any changes to the database, we need to migrate our changes by doing the following in your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python manage.py makemigrations
$ python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Superuser
&lt;/h2&gt;

&lt;p&gt;TO access our database and view the admin page of our app, we need to create a superuser.&lt;br&gt;
Add the following code to your terminal and follow the prompts.&lt;br&gt;
&lt;code&gt;python manage.py createsuperuser&lt;/code&gt;&lt;br&gt;
Then open this &lt;a href="http://127.0.0.1:8000/admin/" rel="noopener noreferrer"&gt;link &lt;/a&gt;in your browser and login with the credentials of the superuser you created.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. User Settings
&lt;/h2&gt;

&lt;p&gt;This page enables a user make changes to his existing profile&lt;br&gt;
First, create settings.html file. check the code &lt;a href="https://github.com/faozziyyah/django-blog-app/blob/main/edublog/templates/settings.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
second, add this to urls.py file, &lt;code&gt;&lt;br&gt;
    path('settings', views.settings, name='settings'),&lt;/code&gt;&lt;br&gt;
Third, Add this to the views.py file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1syuot7a5h4artmdcz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1syuot7a5h4artmdcz1.png" alt="Image description" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How To Build A Blog App With Flask</title>
      <dc:creator>faozziyyah</dc:creator>
      <pubDate>Thu, 05 Jan 2023 11:14:47 +0000</pubDate>
      <link>https://dev.to/faozziyyah/how-to-build-a-blog-app-with-flask-9h2</link>
      <guid>https://dev.to/faozziyyah/how-to-build-a-blog-app-with-flask-9h2</guid>
      <description>&lt;p&gt;In this article, I'll take you through the process of building a blog app with flask and SQLAlchemy for database.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;The features of this project include&lt;/em&gt;&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;responsive website using bootstrap&lt;/li&gt;
&lt;li&gt;add, read, edit and delete a post &lt;/li&gt;
&lt;li&gt;adding comments and images to a post&lt;/li&gt;
&lt;li&gt;authentication and authorization&lt;/li&gt;
&lt;li&gt;message flashing&lt;/li&gt;
&lt;li&gt;display error pages&lt;/li&gt;
&lt;li&gt;database management with mysql and SQLAlchemy&lt;/li&gt;
&lt;li&gt;using the rich text editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flask is a python micro-framework for building web applications and it is easy to learn. You can learn more about it by &lt;a href="https://flask.palletsprojects.com/en/2.1.x/"&gt;visiting this website&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;p&gt;The following are the basic requirements before starting this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/downloads/"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/download"&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com/downloads"&gt;Git bash&lt;/a&gt; or any other terminal&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mysql.com/downloads/"&gt;MySQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. Setting Up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A. Create a Project folder:&lt;/strong&gt; navigate into the section where you want to have your project and type these commands to create a new directory or folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// create a new directory(folder)
$ mkdir blog-app

// navigate into the folder
$ cd blog-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;B. Create a virtual environment:&lt;/strong&gt; A &lt;a href="https://www.geeksforgeeks.org/python-virtual-environment/"&gt;virtual environment&lt;/a&gt; is a tool that helps to keep dependencies required by different projects separate by creating isolated python virtual environments for them. This is one of the most important tools that most Python developers use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// navigate into the folder
$ cd blog-app

// create a virtual environment
$ python3 -m venv venv

// activate the virtual environment
$ . venv/Scripts/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;once activated, the command line shows the name of your virtual environment (venv).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C. Install Flask and SQlAlchemy&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pip install flask
$ pip install Flask-SQLAlchemy
$ pip install pymysql
$ pip install Flask-Login
$ pip install Flask-Migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;D. Create a Flask App:&lt;/strong&gt; you can use this command in your terminal &lt;code&gt;$ touch app.py&lt;/code&gt; to create the file for our flask app or create it manually in VS Code then write this code inside it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;E. Configure the Database:&lt;/strong&gt; open your psql terminal (SQL shell) and create a new database. For this project, I use &lt;em&gt;our_users&lt;/em&gt; as the database name. Thereafter, write this in your app.py file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:password of your MYSQL database@localhost/our_users'

app.config['SECRET_KEY'] = "secret"
db = SQLAlchemy(app)

// this should always be at the bottom of the page
if __name__ == '__main__':
    app.run(debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Database Models
&lt;/h2&gt;

&lt;p&gt;our project data has three database models: Post, Comment and Users.&lt;br&gt;
using the &lt;em&gt;&lt;strong&gt;UserMixin&lt;/strong&gt;&lt;/em&gt;, the Users model create a table of users, linking them to their posts while datetime is important to show the date each post was created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask_login import UserMixin
from datetime import datetime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, we can build the Users, Post and Comment classes using this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#create users model
class Users(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True) 
    username = db.Column(db.String(20), nullable=False, unique=True)
    name = db.Column(db.String(200), nullable=False)
    email = db.Column(db.String(120), nullable=False, unique=True)
    favorite_color = db.Column(db.String(120))
    about_author = db.Column(db.String(500), nullable=True)
    date_added = db.Column(db.DateTime, default=datetime.utcnow)
    profile_pic = db.Column(db.String(200), nullable=True)
    password_hash = db.Column(db.String(128))
    posts = db.relationship('Post', backref='poster', lazy='dynamic')

def __repr__(self):
        return '&amp;lt;Name %r&amp;gt;' % self.name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#create a blog post model
class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255))
    content = db.Column(db.Text)
    author = db.Column(db.String(255))
    date_posted = db.Column(db.DateTime, default=datetime.utcnow)
    slug = db.Column(db.String(255))
    poster_id = db.Column(db.Integer, db.ForeignKey("users.id"))
    comments = db.relationship('Comment', backref='post', lazy='dynamic')
    post_pic = db.Column(db.String(200), nullable=True)

class Comment(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(255))
    text = db.Column(db.Text())
    date = db.Column(db.DateTime())
    post_id = db.Column(db.Integer(), db.ForeignKey('post.id'))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check out &lt;a href="https://docs.sqlalchemy.org/en/14/core/tutorial.html"&gt;this article&lt;/a&gt; for better understanding on how the syntax works.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Database Migrations
&lt;/h2&gt;

&lt;p&gt;Migrations are important to let MYSQL know that we've made changes to our database. First, we write this code in our app.py file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask_migrate import Migrate

# write this after db = SQLAlchemy(app)
migrate = Migrate(app, db)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then we you the following in your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# create migrations folder
$ flask db init

# make changes
$ flask db migrate -m 'comment'
$ flask db upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c&lt;br&gt;
Routing means mapping a URL to a specific Flask function that will handle the logic for that URL using &lt;strong&gt;&lt;em&gt;@app.route()&lt;/em&gt;&lt;/strong&gt;, but first, we need to import a few things from flask using this code&lt;br&gt;
&lt;code&gt;from flask import Flask, render_template, flash, request, redirect, url_for, current_app&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;1. Index or Home Page:&lt;/strong&gt; this page shows all the posts created. This is the homepage of our blog app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# all posts
@app.route('/')
def index():
    flash("Welcome to our website!")
    posts = Post.query.order_by(Post.date_posted)
    return render_template('index.html', post=posts)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we can render our posts on the browser, we need to create an HTML page for that. But first, we need to create a folder called &lt;strong&gt;templates **in our app. Then, we create the **base.html&lt;/strong&gt; and &lt;strong&gt;index.html&lt;/strong&gt; inside the templates folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;

    &amp;lt;link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}"&amp;gt;
    &amp;lt;link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"&amp;gt;
    &amp;lt;script src="{{ url_for('static', filename='js/jquery.js') }}"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src="{{ url_for('static', filename='js/bootstrap.js') }}"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src="{{ url_for('static', filename='js/script.js') }}"&amp;gt;&amp;lt;/script&amp;gt;
    {% block title %}{% endblock %}
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

    &amp;lt;header&amp;gt;
        &amp;lt;!-- Fixed navbar --&amp;gt;
        &amp;lt;nav class="navbar navbar-expand-md navbar-dark"&amp;gt;
          &amp;lt;div class="container-fluid"&amp;gt;
            &amp;lt;a class="navbar-brand" href="{{ url_for('index') }}"&amp;gt; 
              EDUBLOG
            &amp;lt;/a&amp;gt;

            &amp;lt;button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"&amp;gt;
              &amp;lt;span class="navbar-toggler-icon"&amp;gt;&amp;lt;/span&amp;gt;
            &amp;lt;/button&amp;gt;
            &amp;lt;div class="collapse navbar-collapse" id="navbarCollapse"&amp;gt;
              &amp;lt;ul class="navbar-nav me-auto mb-2 mb-md-0"&amp;gt;

                &amp;lt;li class="nav-item"&amp;gt;
                  &amp;lt;a class="nav-link" aria-current="page" href="{{ url_for('add_post') }}"&amp;gt;Add Blog Post&amp;lt;/a&amp;gt;
                &amp;lt;/li&amp;gt;

              &amp;lt;/ul&amp;gt;

              &amp;lt;ul class="navbar-nav  navbar-right"&amp;gt;   

                {% if current_user.is_authenticated %}

                &amp;lt;li class="nav-item"&amp;gt;
                  &amp;lt;a class="nav-link" aria-current="page" href="{{ url_for('admin') }}"&amp;gt;Admin&amp;lt;/a&amp;gt;
                &amp;lt;/li&amp;gt;

                &amp;lt;li class="nav-item"&amp;gt;
                  &amp;lt;a class="nav-link" aria-current="page" href="{{ url_for('dashboard') }}"&amp;gt;Dashboard&amp;lt;/a&amp;gt;
                &amp;lt;/li&amp;gt;

                &amp;lt;li class="nav-item"&amp;gt;
                  &amp;lt;a class="nav-link" aria-current="page" href="{{ url_for('logout') }}"&amp;gt;Logout&amp;lt;/a&amp;gt;
                &amp;lt;/li&amp;gt;

                {% else %}

                &amp;lt;li class="nav-item"&amp;gt;
                  &amp;lt;a class="nav-link" aria-current="page" href="{{ url_for('add_user') }}"&amp;gt;Register&amp;lt;/a&amp;gt;
                &amp;lt;/li&amp;gt;

                &amp;lt;li class="nav-item"&amp;gt;
                  &amp;lt;a class="nav-link" aria-current="page" href="{{ url_for('login') }}"&amp;gt;Login&amp;lt;/a&amp;gt;
                &amp;lt;/li&amp;gt;

                {% endif %}&amp;gt;

              &amp;lt;/ul&amp;gt;

            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/nav&amp;gt;
      &amp;lt;/header&amp;gt;

      &amp;lt;main class="container-fluid main"&amp;gt;
        {% block content %}{% endblock %}
      &amp;lt;/main&amp;gt;

    &amp;lt;footer class=""&amp;gt;
          &amp;lt;span&amp;gt;2022. All rights reserved.&amp;lt;/span&amp;gt;
      &amp;lt;/footer&amp;gt;

      &amp;lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;base.html&lt;/strong&gt; file contains the needed information for all the pages. It also contains some syntax known as &lt;a href="https://jinja.palletsprojects.com/en/3.1.x/"&gt;Jinja&lt;/a&gt;.&lt;br&gt;
"Jinja is a fast, expressive, extensible templating engine. Special placeholders in the template allow writing code similar to Python syntax. Then the template is passed data to render the final document." &lt;/p&gt;
&lt;h2&gt;
  
  
  5. Other Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A. Imports:&lt;/strong&gt; These are necessary for the functionality of the blog app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from turtle import title
from flask import Flask, render_template, flash, request, redirect, url_for, current_app
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField, BooleanField, ValidationError, TextAreaField
from wtforms.validators import DataRequired, EqualTo, Length
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from wtforms.widgets import TextArea
from flask_login import UserMixin, login_user, LoginManager, login_required, logout_user, current_user 
from flask_ckeditor import CKEditor
from flask_ckeditor import CKEditorField
from flask_wtf.file import FileField
from werkzeug.utils import secure_filename
import uuid as uuid
import os
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Authentication and Authorization:&lt;/strong&gt; deals with the login, logout, register and admin features&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Flask_Login Stuff
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

@login_manager.user_loader
def load_user(user_id):
    return Users.query.get(int(user_id))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to create forms which users can use to register and login&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#create form class
class UserForm(FlaskForm):
    name = StringField("Name", validators=[DataRequired()])
    username = StringField("Username", validators=[DataRequired()])
    email = StringField("Email", validators=[DataRequired()])
    favorite_color = StringField("Favorite Color")
    about_author = TextAreaField("About Author")
    password_hash =PasswordField("Password", validators=[DataRequired(), EqualTo('password_hash2', message='Passwords must match')])
    password_hash2 = PasswordField("Confirm Password", validators=[DataRequired()])
    profile_pic = FileField("Profile_pic")
    submit = SubmitField("Submit")

class PasswordForm(FlaskForm):
    email = StringField("What's your email?", validators=[DataRequired()])
    password_hash = PasswordField("What's your password?", validators=[DataRequired()])
    submit = SubmitField("Submit")

# login form
class LoginForm(FlaskForm):
    username = StringField("username", validators=[DataRequired()])
    password = PasswordField("password", validators=[DataRequired()])
    submit = SubmitField("submit")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, we create the login and logout route&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#login user
@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = Users.query.filter_by(username=form.username.data).first()
        if user:
            if check_password_hash(user.password_hash, form.password.data):
                login_user(user)
                flash("Login successful!!")
                return redirect(url_for('dashboard'))
            else:
                flash("Wrong Password, Try Again!")
        else:
            flash("That user does not exist, Try Again!")

    return render_template('login.html', form=form)

# logout 
@app.route('/logout', methods=['GET', 'POST'])
@login_required
def logout():
    logout_user()
    flash("You have logged out!")
    return redirect(url_for('login'))

# delete user
@app.route('/delete/&amp;lt;int:id&amp;gt;')
@login_required
def delete(id):

    if id == current_user.id or id == 8:
        user_to_delete = Users.query.get_or_404(id)
        name = None
        form = UserForm()

        try:
            db.session.delete(user_to_delete)
            db.session.commit()
            flash("user deleted successfully!!")
            our_users = Users.query.order_by(Users.date_added)
            return render_template("add_user.html", form=form, name=name, our_users=our_users)

        except:
            flash("Whoops! Something went wrong, please try again later...")
            return render_template("add_user.html", form=form, name=name, our_users=our_users)
    else:
        flash("Sorry, you can't delete this user!")
        return redirect(url_for('dashboard'))

#update user record
@app.route('/update/&amp;lt;int:id&amp;gt;', methods=['GET', 'POST'])
@login_required
def update(id):
    form = UserForm()
    name_to_update = Users.query.get_or_404(id)
    if request.method == 'POST':
        name_to_update.name = request.form['name']
        name_to_update.email = request.form['email']
        name_to_update.favorite_color = request.form['favorite_color']
        name_to_update.username = request.form['username']
        name_to_update.about_author = request.form['about_author']

        #check for profile pic
        if request.files['profile_pic']:
            name_to_update.profile_pic = request.files['profile_pic']

        #grab image name
            pic_filename = secure_filename(name_to_update.profile_pic.filename)
            #set uuid
            pic_name = str(uuid.uuid1()) + "_" + pic_filename
            #save the image
            saver = request.files['profile_pic']
            #change it to string and save to db
            name_to_update.profile_pic = pic_name

            try:
                db.session.commit()
                saver.save(os.path.join(app.config['UPLOAD_FOLDER'], pic_name))
                flash("user updated successfully!")
                return render_template("update.html", form=form, name_to_update = name_to_update)
            except:
                flash("Error! try again later")
                return render_template("update.html", form=form, name_to_update = name_to_update)

        else:
            db.session.commit()
            flash("user updated successfully!")
            return render_template("update.html", form=form, name_to_update = name_to_update)
    else:
        return render_template("update.html", form=form, name_to_update = name_to_update, id = id)

# register user
@app.route('/user/add', methods=['GET', 'POST'])
def add_user():
    name = None
    form = UserForm()
    if form.validate_on_submit():
        user = Users.query.filter_by(email=form.email.data).first()
        if user is None:
            hashed_pw = generate_password_hash(form.password_hash.data, "sha256")
            user = Users(name=form.name.data, username=form.username.data, email=form.email.data, favorite_color=form.favorite_color.data, password_hash=hashed_pw)
            db.session.add(user)
            db.session.commit()
        name = form.name.data
        form.name.data = ''
        form.username.data = ''
        form.email.data = ''
        form.favorite_color.data = ''
        form.password_hash.data = ''

        flash("User Added successfully!")
    our_users = Users.query.order_by(Users.date_added)
    return render_template("add_user.html", form=form, name=name, our_users=our_users)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Post Operations:&lt;/strong&gt; &lt;a href="https://github.com/faozziyyah/flask-blog-app/tree/main/templates"&gt;check this out&lt;/a&gt; to view all the html pages for the blog.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;To display a single post...&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# individual post
@app.route('/posts/&amp;lt;int:id&amp;gt;', methods=['GET', 'POST'])
def post(id):
    post = Post.query.get_or_404(id)
    return render_template("post.html", post=post)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;to add a post...&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# add post page
@app.route("/add-post", methods=["GET", "POST"])
@login_required
def add_post():
    form = PostForm()
    image_post = None
    if form.validate_on_submit():
        poster = current_user.id

        if request.files['post_pic']:
            #image_post = None
            post_pic = request.files['post_pic']
            pic_filename = secure_filename(post_pic.filename)
            #set uuid
            pic_name = str(uuid.uuid1()) + "_" + pic_filename
            saver = request.files['post_pic']
            #change it to string and save to db
            post_pic = pic_name

        post = Post(title=form.title.data, content=form.content.data, poster_id=poster, slug=form.slug.data, post_pic=post_pic)
        form.title.data = ''
        form.content.data = ''
        form.post_pic.data = ''
        form.slug.data = ''

        db.session.add(post)
        db.session.commit()
        saver.save(os.path.join(app.config['UPLOAD_FOLDER'], pic_name))
        flash("post submitted successfully!")

    return render_template("add_post.html", post_pic=image_post, form=form)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;to update/edit a post...&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#update post
@app.route('/posts/edit/&amp;lt;int:id&amp;gt;', methods=['GET', 'POST'])
@login_required
def edit_post(id):
    posts = Post.query.order_by(Post.date_posted)
    post = Post.query.get_or_404(id)
    form = PostForm()

    if form.validate_on_submit():
        post.title = form.title.data
        #post.author = form.author.data
        form.slug = form.slug.data
        form.content = form.content.data

        db.session.add(post)
        db.session.commit()
        flash("Post updated successfully!")
        return redirect(url_for('post', id=post.id))

    if current_user.id == post.poster_id:
        form.title.data = post.title
        #form.author.data = post.author
        form.slug.data = post.slug
        form.content.data = post.content
        return render_template("edit_post.html", form=form)

    else:
        flash("You aren't authorized to edit this post!")
        return render_template('index.html', post=posts)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;to delete a post...&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# delete post
@app.route('/posts/delete/&amp;lt;int:id&amp;gt;')
@login_required
def delete_post(id):
    post_to_delete = Post.query.get_or_404(id)
    id = current_user.id

    if id == post_to_delete.poster.id or id == 8:

        try:
            db.session.delete(post_to_delete)
            db.session.commit()
            flash.info("Post deleted successfully")
            posts = Post.query.order_by(Post.date_posted)
            return render_template('index.html', post=posts)

        except:
            flash("Whoops! Something went wrong, please try again later")
            posts = Post.query.order_by(Post.date_posted)
            return render_template('index.html', post=posts)

    else:
        flash("You aren't authorized to delete this post!")
        posts = Post.query.order_by(Post.date_posted)
        return render_template('index.html', post=posts)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Error Pages:&lt;/strong&gt; this display the error on a page&lt;br&gt;
&lt;strong&gt;&lt;em&gt;invalid URL... and internal server error...&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# invalid URL
@app.errorhandler(404)
def page_not_found(e):
    return render_template("404.html"), 404

# internal server error
@app.errorhandler(500)
def page_not_found(e):
    return render_template("500.html"), 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks for exploring this article with me!&lt;br&gt;
For the source code: Kindly check out &lt;a href="https://github.com/faozziyyah/flask-blog-app"&gt;Flask-blog-app&lt;/a&gt;, a project I built for the &lt;a href="https://www.altschoolafrica.com/"&gt;AltSchool Africa&lt;/a&gt; second semester examination.&lt;/p&gt;

&lt;p&gt;Special Thanks to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;John Elder for his tutorials on &lt;a href="https://www.youtube.com/watch?v=0Qxtt4veJIc&amp;amp;list=PLCC34OHNcOtolz2Vd9ZSeSXWc8Bq23yEz"&gt;Codemy.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.altschoolafrica.com/schools/engineering"&gt;AltSchool Africa&lt;/a&gt; for their lessons on backend engineering.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>flask</category>
      <category>backend</category>
      <category>python</category>
    </item>
    <item>
      <title>My Goals For KODECAMP Internship</title>
      <dc:creator>faozziyyah</dc:creator>
      <pubDate>Mon, 16 Aug 2021 17:03:51 +0000</pubDate>
      <link>https://dev.to/faozziyyah/my-goals-for-kodecamp-internship-1h8f</link>
      <guid>https://dev.to/faozziyyah/my-goals-for-kodecamp-internship-1h8f</guid>
      <description>&lt;p&gt;Recently joined the KodeCamp internship (&lt;strong&gt;FRONT-END TRACK&lt;/strong&gt;) because I want to improve my knowledge and skills and here are my goals for the 16 weeks internship...&lt;br&gt;
   I'd love to achieve the following by the end of this internship;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Improve my knowledge by learning the core concepts of javascript and Reactjs.&lt;/li&gt;
&lt;li&gt;collaboration and team work.&lt;/li&gt;
&lt;li&gt;Improve my skills in knowledge of front-end development.&lt;/li&gt;
&lt;li&gt;Time management and critical thnking.&lt;/li&gt;
&lt;li&gt;Have a remote job.&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>My Goals For HNG Internship</title>
      <dc:creator>faozziyyah</dc:creator>
      <pubDate>Sun, 15 Aug 2021 11:22:25 +0000</pubDate>
      <link>https://dev.to/faozziyyah/my-goals-for-hng-internship-2aof</link>
      <guid>https://dev.to/faozziyyah/my-goals-for-hng-internship-2aof</guid>
      <description>&lt;p&gt;HNG internship started on Thursday 😊 and the first task that would qualify us to next stage has commenced.&lt;br&gt;
    I join the &lt;strong&gt;Front-end track&lt;/strong&gt; of the HNG 8th internship with an uplifted spirit and a strong determination to get to the final stage because I didn't get to the final stage at the last internship HNGi7. &lt;br&gt;
    I was evicted at stage 3 last because I couldn't complete the task for the next stage 😥, I was a beginner then, just started learning the basics of website development. Even though it was a bit tough then, I enjoyed every bit of it and I gained a so much that I was patiently anticipating the next season of the HNG internship. 😊&lt;br&gt;
   Finally, my dream come true as the HNG season 8 has commenced and I'm happy that I've acquired enough skills to be able to push through to the final stage of this internship and here are my goals;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To get to the final stage of the HNG8 internship and become an alumni. Well T-shits will be given to those that get to the final stage 😅 but for me, it's beyond the T-shirt.&lt;/li&gt;
&lt;li&gt;To connect with other developers and network.&lt;/li&gt;
&lt;li&gt;To improve my skills and learn new skills. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My goal is to also gain these soft skill by the end of the internship;&lt;br&gt;
Communication.&lt;br&gt;
Team work,&lt;br&gt;
Collaboration.&lt;br&gt;
Time Management.&lt;br&gt;
Critical Thinking and &lt;br&gt;
Research and Analysis&lt;/p&gt;

&lt;p&gt;Let's get started as the motivation is to never give up. You can also join the internship here 👇 and I promise you it's going to worth your time.&lt;br&gt;
&lt;a href="https://internship.zuri.team"&gt;Join the HNG8 internship&lt;/a&gt;&lt;br&gt;
Wish me luck and see you there... &lt;/p&gt;

&lt;p&gt;Here's is a resource on designing with figma&lt;br&gt;
&lt;a href="https://www.figma.com/resources/learn-design/"&gt;Figma tutorial&lt;/a&gt;&lt;br&gt;
Here's is a resource on using GIT&lt;br&gt;
&lt;a href="https://www.atlassian.com/git"&gt;GIT tutorial&lt;/a&gt;&lt;br&gt;
Here's is a beginner tutorial for HTML&lt;br&gt;
&lt;a href="https://www.w3schools.com/html/"&gt;Learn HTML&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Javascript Functions. A quick guide..</title>
      <dc:creator>faozziyyah</dc:creator>
      <pubDate>Tue, 16 Mar 2021 08:37:26 +0000</pubDate>
      <link>https://dev.to/faozziyyah/javascript-functions-a-quick-guide-e80</link>
      <guid>https://dev.to/faozziyyah/javascript-functions-a-quick-guide-e80</guid>
      <description>&lt;p&gt;Functions are often used in JavaScript by developers. In fact, it's used in other programming languages like python as well. But in this article, we'll focus on using functions in Javascript.&lt;/p&gt;

&lt;p&gt;Definition of a Function:&lt;br&gt;
A JavaScript function is a block of code designed to perform a particular task.&lt;br&gt;
A JavaScript function is executed when "something" invokes it (calls it).&lt;/p&gt;

&lt;p&gt;There are two types of functions. &lt;br&gt;
✔️ In-built functions&lt;br&gt;
✔️ User defined functions.&lt;/p&gt;

&lt;p&gt;🌟 In-built functions are special functions used to perform special tasks.&lt;br&gt;
An example is the .to precision() function, this is used on number data type and it returns a string of that number but to a certain significant figures based on the argument passed into it. &lt;br&gt;
We also have the .toUpperCase and .to lowercase In-built functions and many other examples.&lt;/p&gt;

&lt;p&gt;🌟 Javascript user defined functions are functions created by the user to perform tasks as well like the example below:&lt;br&gt;
 function name(){&lt;br&gt;
    alert("this is my name!");&lt;br&gt;
}&lt;br&gt;
In the example above, name() is a user defined function.&lt;/p&gt;

&lt;p&gt;✔️ Function parameters: These are the names listed in the function's definition. For example;&lt;br&gt;
 function sayHello(name){&lt;br&gt;
     alert("Hi," + name);&lt;br&gt;
}&lt;br&gt;
sayHello("David");&lt;/p&gt;

&lt;p&gt;Taking a look at this example, the parameter in this function is "name". While the expression sayHello("David") is known as calling the function.&lt;/p&gt;

&lt;p&gt;📌 Therefore, note that for a function to be executed, it has to be called just like in the example above.&lt;/p&gt;

&lt;p&gt;✔️ Multiple parameters: They can be defined with comma separating them. They're the names listed in the function definition. For example;&lt;br&gt;
 function sayHello(name,age){&lt;br&gt;
  document.write(name + "is" + age + "years old");&lt;br&gt;
}&lt;br&gt;
sayHello("John", 20);&lt;/p&gt;

&lt;p&gt;✔️ Function Return: This is used to return a value from the function e.g when making calculation that require a result. For example&lt;br&gt;
 function addNumbers(a,b){&lt;br&gt;
    return a+b;&lt;br&gt;
}&lt;br&gt;
addNumbers(5,6);&lt;/p&gt;

&lt;p&gt;✔️ Anonymous Function: Also known as function expression. This is a function assigned to a variable. For example&lt;br&gt;
 var sayBye = function (){&lt;br&gt;
   console.log("Bye");&lt;br&gt;
}&lt;br&gt;
sayBye();&lt;br&gt;
 To read more on Javascript functions, you can go through this link &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions&lt;/a&gt;&lt;br&gt;
I hope you learnt something new today.&lt;br&gt;
Thank you for reading.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
