Showing posts with label tcs. Show all posts
Showing posts with label tcs. Show all posts

Python FSP - Mini-Project - Sprint7 - Capstone Project - WebFramework || Fresco Play || 72113

Mini-Project - Python FSP - Capstone Project- WebFramework

Instructions

In the Handson env there will be a directory called 'Project' in the Desktop, where you can find the files.

In this challenge, you have to create a blog website in Django application.

Steps:

In models.py, read the instructions and create models.

In forms.py, create form fields as per instructions given in py file.

In views.py, create the following endpoints

  • signup - use 'signup/' route and redirect to login page after successful signup.
  • login - use 'login/' route and redirect to index page after successful login. If the username and password doesn't match show a message as ' incorrect username or password'
  • create - use 'create/' route. On this page user enter blog title and content after successful creation of blog redirect to index page.
  • index - use 'index/' route and this page shows all the blog created by the user. only registered user can view into this page.
  • blog - use 'index/blog/<int:id>/' route. This page display full content of the blog. only registered user can view into this page.

Create html files in the templates folder for these above endpoints.

In urls.py, add these above endpoints with URI and name.

css files are optional

Note: Once you have completed the django application then add and commit the changes to the local git in the directory where the django application resides.

Do not change or modify the test.py and settings.py file.

Jenkins is already installed and you can just run Jenkins by opening chrome and going to (http://localhost:8080)

Configure Jenkins to integrate with Django application

  1. Login to Jenkins with username as admin and fetch password from the path
     $ cat /var/lib/jenkins/secrets/initialAdminPassword
    
  2. Create a freestyle project named Blog in Jenkins.
  3. Configure the source code of your job with Repository URL file:////home/labuser/Desktop/Project/fullstackdev-capstone
  4. In the Add build step, select execute shell and follow the below format to execute the django application,
     # Add the following command in the shell :
     BUILD_ID=dontkillme
     # write a command to install all the dependencies required for the django application
     pip3 install --user -r requirements.txt
     # write a command to migrate the application
     python3 manage.py makemigrations && python3 manage.py migrate --run-syncdb
     # write a command to run the django application in 0.0.0.0:8001 port in background.
     python3 manage.py runserver 0.0.0.0:8001
     # write a command to test the django application
     python3 manage.py test
    
  5. Apply the changes and build your job.
  6. Check your result in console output.
  7. You are done if your console output is Finished: SUCCESS

Solution

  • models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
# from django.core.validators import RegexValidator
"""

create user model
    firstname - textfield
    lastname  - textfield
    username  - textfield must be unique
    email     - emailfield primarykey
    dob       - datefield
    my_photo  - imagefield(optional)

create Blog model
    title     - textfield
    content   - textfield
    created_at- datefield
    blog_photo- imagefield(optional)
    blogger   - manytoone(ForeignKey Field) relationship with user table.

"""


class User(AbstractBaseUser):
    firstname = models.CharField(max_length=100)
    lastname = models.CharField(max_length=100)
    username = models.CharField(max_length=100, unique=True)
    email = models.EmailField(primary_key=True)
    dob = models.DateField()
    my_photo = models.ImageField(upload_to="my_photo", blank=True, null=True)
    # password_validator = RegexValidator(
    #     regex=r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,}$", message="Enter a valid password"
    # )
    password = models.CharField(max_length=128)

    USERNAME_FIELD = "username"
    REQUIRED_FIELDS = ["email"]

    def __str__(self):
        return self.username


class Blog(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateField()
    blog_photo = models.ImageField(upload_to="blog_photo", blank=True, null=True)
    blogger = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.title
  • forms.py
from django import forms
from .models import User, Blog

"""
create loginform with username and password fields
create signupform with the fields matching user model 
create blogform with the fields matching blog model
"""


class loginForm(forms.Form):
    # fields - username, password
    username = forms.CharField(max_length=128)
    password = forms.CharField(widget=forms.PasswordInput)


class signUpForm(forms.ModelForm):
    # fields - firstname, lastname, username, email, password, confirm, dob, my_photo (optional)
    password = forms.CharField(widget=forms.PasswordInput)
    confirm = forms.CharField(widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ["firstname", "lastname", "username", "email", "dob", "my_photo"]
        widgets = {
            "dob": forms.DateInput(attrs={"type": "date"}),
        }

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get("password")
        confirm = cleaned_data.get("confirm")
        if password and confirm and password != confirm:
            self.add_error("confirm", "Passwords do not match.")
        return cleaned_data


class createBlog(forms.ModelForm):
    # fields - title, content, img (optional)
    class Meta:
        model = Blog
        fields = ["title", "content", "blog_photo"]
        widgets = {
            "blog_photo": forms.ClearableFileInput(),
        }
  • views.py
from rest_framework.views import View
from django.forms import ValidationError
from django.shortcuts import render, redirect, get_object_or_404
from .forms import loginForm, signUpForm, createBlog
from .models import Blog, User
import datetime


# instructions are given in problem description
def login(request):
    # get method handler render login.html page
    # post method handler authenticate user credentials, create session and redirect to index page
    if request.method == "GET":
        form = loginForm()
        return render(request, "login.html", {"form": form})
    elif request.method == "POST":
        form = loginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data["username"]
            password = form.cleaned_data["password"]
            try:
                user = User.objects.get(username=username)
                if user and user.check_password(password):
                    request.session["user"] = user.email
                    return redirect("index")
                else:
                    form.add_error("username", "Incorrect username or password")
            except User.DoesNotExist:
                form.add_error("username", "Incorrect username or password")
        return render(request, "login.html", {"form": form})


def signup(request):
    # get method handler render signup.html
    # post method handler save the user data and redirects to login page
    #
    if request.method == "GET":
        form = signUpForm()
        return render(request, "signup.html", {"form": form})
    elif request.method == "POST":
        form = signUpForm(request.POST, request.FILES)

        if form.is_valid():
            user = form.save(commit=False)
            user.set_password(form.cleaned_data["password"])
            user.save()
            return redirect("login")

        print(form.errors)
        return render(request, "signup.html", {"form": form})


class create_blog(View):
    # get method handler render create.html
    # post method handler if the create button is clicked, get the title and content field from form, save it and redirect to index page
    def get(self, request):
        if not request.session.get("user"):
            return redirect("login")

        user_email = request.session.get("user")
        user = User.objects.get(email=user_email)

        form = createBlog()
        return render(request, "create.html", {"form": form, "user": user})

    def post(self, request):
        if not request.session.get("user"):
            return redirect("login")

        user_email = request.session.get("user")
        user = User.objects.get(email=user_email)
        form = createBlog(request.POST, request.FILES)
        if form.is_valid():
            blog = form.save(commit=False)
            blog.blogger = user
            blog.created_at = datetime.datetime.now()
            blog.save()
            return redirect("index")
        return render(request, "create.html", {"form": form, "user": user})


def logout(request):
    # get method handler removes the session and redirects to login page
    request.session.flush()
    return redirect("login")


class index(View):
    # get method handler shows the list of blogs render index.html
    def get(self, request):
        user_email = request.session.get("user")
        if not user_email:
            return redirect("login")
        user = User.objects.get(email=user_email)
        blogs = Blog.objects.filter(blogger_id=user_email).order_by("-created_at")
        return render(request, "index.html", {"blogs": blogs, "user": user})


class blog(View):
    # get method handler shows the detailed view of blog rendering blog.html
    def get(self, request, blog_id):
        user_email = request.session.get("user")
        if not user_email:
            return redirect("login")
        user = User.objects.get(email=user_email)
        blog_post = get_object_or_404(Blog, id=blog_id)
        return render(request, "blog.html", {"blog": blog_post, "user": user})
  • urls.py
"""Play URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""

from django.contrib import admin
from django.urls import path
from django.conf.urls.static import static
from .views import login, logout, signup, create_blog, index, blog

urlpatterns = [
    path("admin/", admin.site.urls),
    path("login/", login, name="login"),
    path("signup/", signup, name="signup"),
    path("create/", create_blog.as_view(), name="blog_create"),
    path("index/", index.as_view(), name="index"),
    path("index/blog/<int:blog_id>/", blog.as_view(), name="blog_detail"),
    path("logout/", logout, name="logout"),
]
  • Below are the files in templates

base.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@200,400,600&display=swap" rel="stylesheet" />
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>
      {% block title %}

      {% endblock %}
    </title>
    <style>
      * {
        border-style: none;
        border-radius: 5px;
        padding: 0;
        margin: 0;
      }
      .errorlist {
        list-style: none;
        color: #d43131;
        font-size: small;
      }

      body {
        background-color: #d2fdff;
        font-family: 'Poppins', sans-serif;
        padding: 0%;
        margin: 0%;
        width: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 99vh;
      }

      div {
        padding: 5px;
        margin: 5px;
        display: inline;
      }

      input {
        float: right;
        display: flex;
        align-items: center;
        justify-content: space-around;
        padding: 6px;
      }

      #err {
        display: inline-block;
        right: 10%;
      }

      #card {
        border-radius: 5px;
        padding: 0.5rem;
        display: flex;
        flex-direction: column;
        gap: 1rem;
        justify-content: center;
        align-items: center;
        background-color: #f4bc8a;
        width: 100%;
      }

      #card th,
      .card th {
        text-align: left;
        padding: 0.25rem;
      }

      #card form {
        gap: 0.25rem;
      }

      #card form button {
        margin-top: 0.5rem;
      }

      form {
        display: flex;
        justify-content: center;
        flex-direction: column;
        max-width: 100%;
        width: 600px;
      }

      h2 {
        text-align: center;
        padding-bottom: 0.5rem;
      }

      button,
      .btn {
        /* Spans both columns */
        padding: 10px;
        background-color: #0e9db3;
        color: white;
        border: none;
        font-size: small;
      }

      .nav-bar {
        top: 0;
        position: fixed;
        overflow: hidden;
        z-index: 2;
        margin-top: 0px;
        float: right;
        height: 2em;
        border-radius: 3px;
        width: 100%;
        background-color: white;
        padding: 0.5rem;
        display: flex;
      }
      .nav-bar ul {
        display: flex;
        flex-direction: row;
        gap: 0.5rem;
        list-style-type: none;
        margin: 0;
        padding: 0.5rem;
        overflow: hidden;
      }
      .nav-bar .inline-form {
        margin-left: auto;
      }
      .inline-form {
        display: inline-block;
        width: initial;
      }
      main {
        width: 100vh;
        padding: 0.5rem;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .c {
        display: flex;
        flex-direction: column;
      }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  </head>

  <body>
    <header class="nav-bar">
      <ul>
        <li>
          <a href="{% url 'index' %}">Home</a>
        </li>

        {% if user.email is None %}
          <li>
            <a href="{% url 'login' %}">Login</a>
          </li>
          <li>
            <a href="{% url 'signup' %}">Signup</a>
          </li>
        {% else %}
          <li>
            <a href="{% url 'blog_create' %}"> Create +</a>
          </li>
        {% endif %}
      </ul>

      {% if user.email is not None %}
        <form class="inline-form" action="{% url 'logout' %}" method="POST">
          {% csrf_token %}
          <!-- logout button -->
          <button type="submit">Logout</button>
        </form>
      {% endif %}
    </header>
    {% block content %}

    {% endblock %}
  </body>
</html>

index.html

{% extends 'base.html' %}
{% block title %}
  {{ title }}
{% endblock %}

{% block content %}
  <style>
    .bcard {
      border: 1px solid #1f85de;
      display: flex;
      justify-content: center;
      align-items: flex-start;
      flex-direction: column;
      width: 100%;
      max-width: 600px;
    }

    .single {
      display: flex;
      justify-content: space-evenly;
      align-items: stretch;
      margin: 0.5rem;
      background-color: #1f85de;
      color: #fff;
      flex-direction: row;
    }

    main a {
      text-decoration: none;
      color: #fff;
      font-weight: bold;
    }
  </style>
  <!-- write your script to display blog created by current user here -->
  <main class="c">
    {% if blogs %}
      <h2>Here are your blogs:</h2>

      <ul class="bcard">
        {% for blog in blogs %}
          <li class="single">
            <h3><a href="{% url 'blog_detail' blog.id %}">{{ blog.title }}</a></h3>
            <div class="c">
              <p>{{ blog.content|truncatechars:50 }}</p>
              <p>{{ blog.created_at }}</p>
            </div>
          </li>
        {% endfor %}
      </ul>
    {% else %}
      <h2>You have not created any blogs yet.</h2>
    {% endif %}
  </main>
{% endblock %}

blog.html

{%extends 'base.html'%}
{% block title%}
{{blog.title}}
{%endblock%}

{%block content%}
<!-- write your html script to display the all users blog here -->
<main class="c">
    <h2>{{ blog.title }}</h2>
    {% if blog.image %}<img class="blog-image" src="{{ blog.image.url }}" alt="{{ blog.title }}">{% endif %}
    <p>
        <small>Written by: {{ blog.blogger.username }}</small> <br>
        <small>Published on: {{ blog.created_at }}</small>
    </p>
    <div class="content">
        {{ blog.content }}
    </div>
</main>
{%endblock%}

create.html

{% extends 'base.html' %}
{% block title %}
  Create Blog
{% endblock %}

{% block content %}
  <!-- create form in that user can create their blog -->
  <main>
      <form action="{% url 'blog_create' %}" method="POST">
        <h2>Blog Create Form</h2>
      {% csrf_token %}
      <table id="card">{{ form }}</table>
      <button type="submit">Create</button>
    </form>
  </main>
{% endblock %}

login.html

{% extends 'base.html' %}
{% block title %}
  Login
{% endblock %}
{% block content %}
  <!-- create your login form here -->
  <main>
      <form action="{% url 'login' %}" method="POST">
        <h2>Login Form</h2>
      {% csrf_token %}
      <table id="card">{{ form }}</table>
      <button type="submit">Login</button>
    </form>
  </main>
{% endblock %}

signup.html

{% extends 'base.html' %}
{% block title %}
  signup
{% endblock %}

{% block content %}
  <!-- create signup form here -->
  <main>
    <h2>Signup Form</h2>
    <form action="{% url 'signup' %}" method="POST">
      {% csrf_token %}
      <table id="card">
          {{ form }}
      </table>
      <button type="submit">Signup</button>
    </form>
  </main>
{% endblock %}
  • DevOps Jenkins build shell:
# Add the following command in the shell :
BUILD_ID=dontkillme
# write a command to install all the dependencies required for the django application
pip3 install --user -r requirements.txt
# write a command to migrate the application
python3 manage.py makemigrations && python3 manage.py migrate --run-syncdb
# write a command to run the django application in 0.0.0.0:8001 port in background.
# nohup python3 manage.py runserver 0.0.0.0:8001
# write a command to test the django application
python3 manage.py test
  • user_test_function.py
from django.test import Client, TestCase
from django.urls import reverse
from Play.models import User, Blog


class Test_activity(TestCase):
    def setUp(self):
        csrf_client = Client(enforce_csrf_checks=True)
        self.c = Client()

    def test_index_url(self):
        '''
        Write a code to check the index page is existing or not.
        '''
        response = self.c.get(reverse("index"))
        self.assertIn(response.status_code, [302, 200])  # redirect to login or show page

    def test_new_user(self):
        '''
        Check the user is able to signup with the following details :
        username : user01
        password : user@12345
        firstname: user01
        lastname : user
        email    : user01@leaf.com
        confirm  : user@12345
        dob      : 1999-01-01
        Write a code to check the user is able to login with the credentials :
        Username : user01
        Password : user@12345
        '''
        signup_data = {
            "username": "user01",
            "password": "user@12345",
            "confirm": "user@12345",
            "firstname": "user01",
            "lastname": "user",
            "email": "user01@leaf.com",
            "dob": "1999-01-01"
        }
        response = self.c.post(reverse("signup"), data=signup_data)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(User.objects.count(), 1)

        login_data = {'username':'user01','password':'user@12345','login':'login'}
        response = self.c.post(reverse("login"), data=login_data)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(self.c.session["user"], "user01@leaf.com")

    def test_login(self):
        '''
        Write a code to check the user is able to signup and login with the following details :
        Username  : user02
        Password  : user@12345
        firstname : user
        lastname  : 02
        email : user2@email.com
        dob : 2020-01-01
        '''
        signup_data = {
            "username": "user02",
            "password": "user@12345",
            "confirm": "user@12345",
            "firstname": "user",
            "lastname": "02",
            "email": "user2@email.com",
            "dob": "2020-01-01"
        }
        response = self.c.post(reverse("signup"), data=signup_data)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(User.objects.count(), 1)

        login_data = {'username':'user02','password':'user@12345','login':'login'}
        response = self.c.post(reverse("login"), data=login_data)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(self.c.session["user"], "user2@email.com")

    def test_create(self):
        '''
        Write a code to check signup and login with the details given for the "test_login" function.
        Then verify it is able to create blog with the Title and Content as "First blog" and "This is the first blog in this page."
        '''
        # Signup
        signup_data = {
            "username": "user02",
            "password": "user@12345",
            "confirm": "user@12345",
            "firstname": "user",
            "lastname": "02",
            "email": "user2@email.com",
            "dob": "2020-01-01"
        }
        self.c.post(reverse("signup"), data=signup_data)

        # Login
        login_data = {
            "username": "user02",
            "password": "user@12345"
        }
        self.c.post(reverse("login"), data=login_data)

        # Blog creation
        blog_data = {'title': 'First blog', 'content': 'This is the first blog in this page.', 'create_blog':'create_blog'}
        response = self.c.post(reverse("blog_create"), data=blog_data)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(Blog.objects.count(), 1)
        self.assertEqual(Blog.objects.first().title, "First blog")

Output

Blog Post Page
Blog Create Form Page
Blog Index Page
Login Form Page
Signup Form Page
Share:

Python FSP - Mini-Project - Sprint4- Python Django || Fresco Play || 72110

1. Django - Todo App

In this Challenge, you are supposed to create a Todo App using Django, that should allow the users to add tasks and mark as completed

Steps to complete the challenge:

  • Click Run --> Install option from the project menu to install all required libraries.
  • Click Run --> Run to run your application
  • Click Run --> Open Preview, to view the running application.
  • Click Run tests to test your application and click Submit to end the test.

MODEL:

It will have one table Todo, with the following fields and data types

  • name - CharField
  • task - CharField
  • completed - BooleanField

Create the following endpoints with functionalities as per the instructions below:

  • '/' - This endpoint should render the home page of the app and it is used to add the tasks

    Input fields user name and task

    Response: Should display the alert message after the task is added as given in the image below

  • 'task_view/' - This endpoints should show the list of tasks added to the database and Create a button for the each task to switch and mark the task as "Completed and Not Completed(default value)\". If no task is added, it should display the message NO TASKS HERE.

    Refer the image given below

    Note: Create a common Navigation bar for the both the pages, nav bar should have the following elements and redirect to the corresponding pages

    Todo --> Home Page - '/'

    View Tasks --> View Tasks - '/task_view'

  • 'cross/<id>/' - Used to mark the task as completed and strike the task

  • 'uncross/<id>/' - Used to mark the task as not completed and remove the strike

Software Instructions

This question requires Python 2 and Django 1.11.5.

Install Python and Django

Git Instructions

Use the following commands to work with this project

  • Run

     python3 manage.py makemigrations; python3 manage.py migrate --run-syncdb; python3 manage.py runserver 0.0.0.0:8000
    
  • Test

     py.test -v taskTodo/test_case.py --junitxml=\"result.xml\"
    
  • Install

     python3 -m pip install --user --upgrade pip; pip3 install --user pytest django pytest-django
    

Solution

  • taskTodo/models.py
from django.db import models

# Create your models here.
class Todo(models.Model):
    name = models.CharField(max_length=255)
    task = models.CharField(max_length=255)
    completed = models.BooleanField(default=False)
  • taskTodo/admin.py
from django.contrib import admin
from .models import Todo

# Register your models here.
class TodoAdmin(admin.ModelAdmin):
    pass

admin.site.register(Todo, TodoAdmin)
  • taskTodo/views.py
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from .models import Todo
from django.contrib import messages


# Create your views here.
def index(request):
    if request.method == "GET":
        return render(request, "index.jinja")
    if request.method == "POST":
        try:
            name = request.POST.get("name")
            task = request.POST.get("task")
            todo = Todo(name=name, task=task)
            todo.save()
            messages.add_message(request, messages.SUCCESS, "Task added successfully")
        except:
            messages.add_message(request, messages.ERROR, "Something went wrong")
        return HttpResponseRedirect("/")
    return HttpResponse("Method not allowed", status=405)


def task_view(request):
    if request.method == "GET":
        todos = Todo.objects.all()
        context = {"todos": todos}
        return render(request, "task_view.jinja", context)
    return HttpResponse("Method not allowed", status=405)


def cross_task(request, id):
    if request.method == "POST":
        try:
            todo = Todo.objects.get(id=id)
            todo.completed = True
            todo.save()
            messages.add_message(request, messages.SUCCESS, "Task updated successfully")
        except:
            messages.add_message(request, messages.ERROR, "Something went wrong")
        return HttpResponseRedirect("/task_view")
    return HttpResponse("Method not allowed", status=405)


def uncross_task(request, id):
    if request.method == "POST":
        try:
            todo = Todo.objects.get(id=id)
            todo.completed = False
            todo.save()
            messages.add_message(request, messages.SUCCESS, "Task updated successfully")
        except:
            messages.add_message(request, messages.ERROR, "Something went wrong")
        return HttpResponseRedirect("/task_view")
    return HttpResponse("Method not allowed", status=405)
  • todoApp/urls.py
from django.contrib import admin
from django.urls import path, include
from taskTodo import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index, name='index'),
    path('task_view/', views.task_view, name='task_view'),
    path('cross/<int:id>/', views.cross_task, name='cross_task'),
    path('uncross/<int:id>/', views.uncross_task, name='uncross_task'),
]
  • todoApp/templates/layout.jinja
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>{% block title %}Django ToDo{% endblock title %}</title>
        <link rel="stylesheet" href="https://bootswatch.com/5/brite/bootstrap.min.css" />
    </head>
    <body class="bg-light">
        <header>
            <nav class="navbar navbar-expand-lg navbar-light">
                <div class="container-fluid">
                    <a class="navbar-brand" href="/">Todo</a>
                    <button
                        class="navbar-toggler"
                        type="button"
                        data-bs-toggle="collapse"
                        data-bs-target="#navbarSupportedContent"
                        aria-controls="navbarSupportedContent"
                        aria-expanded="false"
                        aria-label="Toggle navigation"
                    >
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="collapse navbar-collapse" id="navbarSupportedContent">
                        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                            <li class="nav-item">
                                <a class="nav-link active" aria-current="page" href="/task_view">View Tasks</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
        </header>
        <main class="container-fluid">
            {% block content %}{% endblock content %}
        </main>
        <footer></footer>
        <script
            src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-k6d4wzSIapyDyv1kpU366/PK5hCdSbCRGRCMv+eplOQJWyd1fbcAu9OCUj5zNLiq"
            crossorigin="anonymous"
        ></script>
        {% block scripts %}

        {% endblock scripts %}
    </body>
</html>
  • todoApp/templates/index.jinja
{% extends "layout.jinja" %}

{% block content %}
<div class="container-fluid py-4 bg-white">
    <h1 class="text-center">Add your Tasks below</h1>

    {% for message in messages %}
        <div class="alert alert-{{ message.tags }}" role="alert">
            {{ message }}
        </div>
    {% endfor %}

    <form action="/" class="mx-auto" style="max-width: 20rem;" method="POST">
        {% csrf_token %}
        <div class="mb-3">
            <label class="form-label" for="name">User:</label>
            <input class="form-control" type="text" name="name">
        </div>
        <div class="mb-3">
            <label class="form-label" for="task">Task:</label>
            <input class="form-control" type="text" name="task">
        </div>
        <button class="d-block btn btn-success mx-auto" type="submit">Add Task</button>
    </form>
</div>
{% endblock content %}
  • todoApp/templates/task_view.jinja
{% extends "layout.jinja" %}

{% block content %}
<div class="container-fluid py-4 bg-white">
    <h1 class="text-center">List of Tasks</h1>

    {% for message in messages %}
        <div class="alert alert-{{ message.tags }}" role="alert">
            {{ message }}
        </div>
    {% endfor %}

    <table class="table mx-auto" style="max-width: 40rem; width: 100%;">
        <thead>
            <tr>
                <th scope="col">User Name</th>
                <th scope="col">Task</th>
                <th scope="col">Status</th>
            </tr>
        </thead>
        <tbody>
            {% for todo in todos %}
            <tr>
                <td>{{ todo.name }}</td>
                <td class="{%if todo.completed %}text-success text-decoration-line-through{%endif%}">{{ todo.task }}
                </td>
                <td>
                    {%if todo.completed %}
                    <form action="/uncross/{{ todo.id }}/" class="d-inline" method="post">
                        {% csrf_token %}
                        <button type="submit" class="btn btn-link">Completed</button>
                    </form>
                    {%else%}
                    <form action="/cross/{{ todo.id }}/" class="d-inline" method="post">
                        {% csrf_token %}
                        <button type="submit" class="btn btn-link">Not Completed</button>
                    </form>
                    {%endif%}
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</div>
{% endblock content %}
  • todoApp/settings.py
...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            "templates"
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
...
Share: