Web Frameowrk – Shishir Kant Singh https://shishirkant.com Jada Sir जाड़ा सर :) Tue, 18 Apr 2023 08:18:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.9 https://shishirkant.com/wp-content/uploads/2020/05/cropped-shishir-32x32.jpg Web Frameowrk – Shishir Kant Singh https://shishirkant.com 32 32 187312365 Django UpdateView https://shishirkant.com/django-updateview/?utm_source=rss&utm_medium=rss&utm_campaign=django-updateview Tue, 18 Apr 2023 08:17:59 +0000 https://shishirkant.com/?p=3733 Defining the UpdateView class

The UpdateView class allows you to create a class-based view that:

  • Display a form for editing an existing object.
  • Redisplay the form if it has validation errors.
  • Save changes of the object to the database.

The form is generated automatically from the object’s model unless you explicitly specify a form class.

To demonstrate the Django UpdateView class, we’ll create a view that edits a task of the Todo App.

To do that we modify the views.py of the todo app and define the TaskUpdate class that inherits from the UpdateView class like this:

# ...
from django.views.generic.edit import CreateView, UpdateView
from django.contrib import messages
from django.urls import reverse_lazy
from .models import Task


class TaskUpdate(UpdateView):
    model = Task
    fields = ['title','description','completed']
    success_url = reverse_lazy('tasks')
    
    def form_valid(self, form):
        messages.success(self.request, "The task was updated successfully.")
        return super(TaskUpdate,self).form_valid(form)

# ...Code language: Python (python)

How it works.

First, import the UpdateView from the django.views.generic.edit:

from django.views.generic.edit import CreateView, UpdateViewCode language: Python (python)

Second, define the TaskUpdate class that inherits from the UpdateView class. In the TaskUpdate class define the following attributes and methods:

  • model specifies the class of the object to be edited. Because we specify the Task as the model in this example.
  • fields is a list that specifies the form fields. In this example, we use title, description, and completed fields.
  • success_url is the target URL (task list) that Django will redirect to once a task is updated successfully.
  • form_valid() – the method is called once the form is posted successfully. In this example, we create a flash message and return the result of the form_valid() method of the superclass.

By default, the TaskUpdate class uses the task_form.html template from the templates/todo directory. Note that the CreateView and UpdateView classes share the same template name.

If you want to use a different template name, you can specify it using the template_name attribute.

Creating the task_form.html template

Modify the task_form.html template that shows the Update Task heading if the task variable is available in the template (editing mode) or Create Task otherwise (creating mode).

{%extends 'base.html'%}

{%block content%}

<div class="center">
 <form method="post" novalidate class="card">
 	{%csrf_token %}
 	<h2>{% if task %} Update {%else %} Create {%endif%} Task</h2>
	{% for field in form %}
		{% if field.name == 'completed' %}
			<p>
				{{ field.label_tag }}
				{{ field }}
			</p>
			{% if field.errors %}
        		<small class="error">{{ field.errors|striptags  }}</small> 
        	{% endif %}
		{% else %}
    		{{ field.label_tag }} 
        	{{ field }}
        	{% if field.errors %}
        		<small class="error">{{ field.errors|striptags  }}</small> 
        	{% endif %}
        {% endif %}
	{% endfor %}
	
	<div class="form-buttons">
		<input type="submit" value="Save" class="btn btn-primary"/>
		<a href="{%url 'tasks'%}" class="btn btn-outline">Cancel</a>
	</div>
	

</form>
</div>

{%endblock content%}
Code language: HTML, XML (xml)

Defining a route

Define a route in the urls.py of the todo app that maps a URL with the result of the as_view() method of the TaskUpdate class:

from django.urls import path
from .views import (
    home, 
    TaskList, 
    TaskDetail, 
    TaskCreate, 
    TaskUpdate
)


urlpatterns = [
    path('', home, name='home'),
    path('tasks/', TaskList.as_view(),name='tasks'),
    path('task/<int:pk>/', TaskDetail.as_view(),name='task'),
    path('task/create/', TaskCreate.as_view(),name='task-create'),
    path('task/update/<int:pk>/', TaskUpdate.as_view(),name='task-update'),
]
Code language: Python (python)

Including an edit link

Modify the task_list.html template to include the edit link for each task on the task list:

{%extends 'base.html'%}

{%block content%}

<div class="center">
	<h2>My Todo List</h2>
	{% if tasks %}
	<ul class="tasks">
		{% for task in tasks %}
			<li><a href="{% url 'task' task.id %}" class="{% if task.completed%}completed{%endif%}">{{ task.title }}</a> 
				 <div  class="task-controls">
				 	<a href="#"><i class="bi bi-trash"></i> </a>
					<a href="{%url 'task-update' task.id %}"><i class="bi bi-pencil-square"></i></a>
		         </div>
		    </li>
		{% endfor %}
	{% else %}
		<p>🎉 Yay, you have no pending tasks! <a href="{%url 'task-create'%}">Create Task</a></p>
	{% endif %}
	</ul>
</div>
{%endblock content%}
Code language: HTML, XML (xml)

If you edit a task from the todo list by appending three asterisks (***) to the title and mark the task as completed:

Click the Save button and you’ll see that the title and status of the task are updated:

Summary

  • Define a new class that inherits from the UpdateView class to create a class-based view that edits an existing object.
]]>
3733
Django CreateView https://shishirkant.com/django-createview/?utm_source=rss&utm_medium=rss&utm_campaign=django-createview Tue, 18 Apr 2023 08:15:51 +0000 https://shishirkant.com/?p=3729 Defining the CreateView class

The CreateView class allows you to create a class-based view that displays a form for creating an object, redisplaying the form with validation errors, and saving the object into the database.

To use the CreateView class, you define a class that inherits from it and add some attributes and methods.

For example, the following uses the CreateView class to define a class-based view that renders a form for creating a new task in the Todo app:

# ..
from django.views.generic.edit import CreateView
from django.contrib import messages
from django.urls import reverse_lazy
from .models import Task

class TaskCreate(CreateView):
    model = Task
    fields = ['title','description','completed']
    success_url = reverse_lazy('tasks')
    
   
    def form_valid(self, form):
        form.instance.user = self.request.user
        messages.success(self.request, "The task was created successfully.")
        return super(TaskCreate,self).form_valid(form)

# other classes & functionsCode language: Python (python)

How it works:

First, import the CreateView class, the reverse_lazy() function, and messages module.

Second, define the TaskCreate class that inherits from the CreateView class. In the CreateView class, we define the following attributes and methods:

  • model specifies the class of the object to be created (Task).
  • fields is a list of fields that display on the form. In this example, the form will display title, description, and completed attributes of the Task model.
  • success_url is the target URL that Django will redirect to once a task is created successfully. In this example, we redirect to the task list using the reverse_lazy() function. The reverse_lazy() accepts a view name and returns an URL.
  • form_valid() – is a method called once the form is posted successfully. In this example, we set the user to the currently logged user, create a flash message, and return the result of the form_valid() method of the superclass.

By default, the CreateView class uses the task_form.html template from the templates/todo with the following naming convention:

model_form.htmlCode language: Python (python)

If you want to use a different template, you can override the default template using the template_name attribute in the TaskCreate class.

Creating the task_form.html template

Create the task_form.html in the templates/todo directory with the following code:

{%extends 'base.html'%}

{%block content%}

<div class="center">
	<form method="post" novalidate class="card">
	 	{%csrf_token %}
	 	
	 	<h2>Create Task</h2>
		{% for field in form %}
			{% if field.name == 'completed' %}
				<p>
					{{ field.label_tag }}
					{{ field }}
				</p>
				{% if field.errors %}
	        		<small class="error">{{ field.errors|striptags  }}</small> 
	        	{% endif %}
			{% else %}
	    		{{ field.label_tag }} 
	        	{{ field }}
	        	{% if field.errors %}
	        		<small class="error">{{ field.errors|striptags  }}</small> 
	        	{% endif %}
	        {% endif %}
		{% endfor %}
		
		<div class="form-buttons">
			<input type="submit" value="Save" class="btn btn-primary"/>
			<a href="{%url 'tasks'%}" class="btn btn-outline">Cancel</a>
		</div>
	</form>
</div>

{%endblock content%}Code language: HTML, XML (xml)

In the task_form.html, we render the form fields manually. If you want to automatically generate the form, you can use one of the following attributes:

{{ form.as_p }}   # render the form as <p>
{{ form.as_div }} # render the form as <div>
{{ form.as_ul }}  # redner the form as <ul>Code language: Python (python)

Defining the route

Add a route to the urls.py of the todo application by mapping an URL with the result of the as_view() method of the TaskCreate class:

from django.urls import path
from .views import home, TaskList, TaskDetail, TaskCreate

urlpatterns = [
    path('', home, name='home'),
    path('tasks/', TaskList.as_view(),name='tasks'),
    path('task/<int:pk>/', TaskDetail.as_view(),name='task'),
    path('task/create/', TaskCreate.as_view(),name='task-create'),
]Code language: Python (python)

Displaying flash messages & adding a link to the navigation

Modify the base.html template of the project to:

  • Display the flash messages.
  • Add the New Task link to the navigation.
{%load static %}
<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="{% static 'css/style.css' %}" />
        <title>Todo List</title>
    </head>

    <body>
        <header class="header">
            <div class="container">
            	<a href="{%url 'home'%}" class="logo">Todo</a>
                <nav class="nav">
                	<a href="{% url 'home'%}"><i class="bi bi-house-fill"></i> Home</a>
                	<a href="{% url 'tasks' %}"><i class="bi bi-list-task"></i> My Tasks</a>
                	<a href="{% url 'task-create' %}"><i class="bi bi-plus-circle"></i> Create Task</a>
                </nav>
            </div>
        </header>
        <main>
            <div class="container">
            	{% if messages %}
				{% for message in messages %}
					<div class="alert alert-{{message.tags}}">
					       {{message}}
					     </div>
					   {% endfor %}
				{% endif %}
            
             {%block content %}
             {%endblock content%}
            </div>
        </main>
        <footer class="footer">
            <div class="container">
				<p>© Copyright {% now "Y" %} by <a href="https://www.shishirkant.com">Python Tutorial</a></p>
            </div>
        </footer>
    </body>

</html>
Code language: HTML, XML (xml)

Run the Django dev server and open the URL http://127.0.0.1:8000/task/create/, you’ll see the following form:

Enter the title and description and click the Save button, you’ll be redirected to the task list page with a message:

Summary

  • Use the Django CreateView class to define a class-based view that creates an object.
]]>
3729
Django DetailView https://shishirkant.com/django-detailview/?utm_source=rss&utm_medium=rss&utm_campaign=django-detailview Tue, 18 Apr 2023 08:12:38 +0000 https://shishirkant.com/?p=3725 Defining a DetailView

The Django DetailView allows you to define a class-based view that displays the details of an object. To use the DetailView class, you define a class that inherits from the DetailView class.

For example, the following defines the TaskDetail class-based view that displays the detail of a task of the Todo app:

from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from .models import Task

    
class TaskDetail(DetailView):
    model = Task
    context_object_name = 'task'
    
#...  Code language: Python (python)

How it works.

First, import the DetailView from the django.views.generic.detail:

from django.views.generic.detail import DetailViewCode language: Python (python)

Second, define a TaskDetail class that inherits from the DetailView class. In the TaskDetail class, we define the following attributes:

  • model specifies the class of the object that will be displayed.
  • context_object_name specifies the name of the object in the template. By default, Django uses object as the object name in the template. To make it more obvious, we use the task as the object name instead.

By default, the TaskDetail class will load the template with the name task_detail.html from the templates/todo application.

If you want to use a different template name, you can use the template_name attribute in the TaskDetail class.

Create the task_detail.html template

Create the task_detail.html template in the templates/blog directory with the following code:

{%extends 'base.html'%}

{%block content%}

 <article class="task">
	<header>
		<h2>{{ task.title }}</h2>
		<span class="badge {% if task.completed %}badge-completed{% else %}badge-pending{%endif%}">
			{% if task.completed %} Completed {%else%} Pending {%endif%}
		</span>
	</header>
	<p>{{task.description}}</p>
</article>

{%endblock content%}Code language: HTML, XML (xml)

The task_detail.html template extends base.html template.

The task_detail.html template uses the task as the object and displays the task’s attributes including title, status (completed or not), and description.

Defining a route

Define a route that maps the URL that displays a task with the result of the as_view() method of the TaskDetail class:

from django.urls import path
from .views import home, TaskList, TaskDetail

urlpatterns = [
    path('', home, name='home'),
    path('tasks/', TaskList.as_view(),name='tasks'),
    path('task/<int:pk>/',TaskDetail.as_view(),name='task'),
]Code language: Python (python)

The URL accepts an integer as the id (or primary key, pk) of the task. The TaskDetail will take this pk parameter, select the task from the database by the id, construct a Task object and pass it to a template.

Modifying the task_list.html template

Modify the task_list.html template to include the link to each task on the task list using the url tag:

{%extends 'base.html'%}

{%block content%}

<div class="center">
	<h2>My Todo List</h2>
	{% if tasks %}
	<ul class="tasks">
		{% for task in tasks %}
			<li><a href="{% url 'task' task.id %}" class="{% if task.completed%}completed{%endif%}">{{ task.title }}</a> 
				 <div  class="task-controls">
				 	<a href="#"><i class="bi bi-trash"></i> </a>
					<a href="#"><i class="bi bi-pencil-square"></i></a>
		         </div>
		    </li>
		{% endfor %}
	{% else %}
		<p>🎉 Yay, you have no pending tasks!</p>
	{% endif %}
	</ul>
</div>
{%endblock content%}
Code language: HTML, XML (xml)

When you click the link of each tag, you’ll be redirected to the task detail page.

Run the Django dev server:

python manage.py runserverCode language: plaintext (plaintext)

and open the task list:

http://127.0.0.1:8000/tasks/Code language: plaintext (plaintext)

you’ll see the following task list:

And click a task e.g., Learn Python, you’ll be redirected to the task detail page:

Summary

  • Use Django DetailView to display the detail of an object.
]]>
3725
Django ListView https://shishirkant.com/django-listview/?utm_source=rss&utm_medium=rss&utm_campaign=django-listview Tue, 18 Apr 2023 08:10:40 +0000 https://shishirkant.com/?p=3721 Introduction to the class-based views

In the previous tutorials, you have learned how to build a blog application using function-based views.

The function-based views are simple but flexible. In the earlier versions, Django only supported function-based views. Later, Django added support for class-based views that allow you to define views using classes.

Class-based views are an alternative way to implement views. They do not replace the function-based views. However, they have some advantages in comparison with the function-based views:

  • Organize code related to HTTP methods like GET and POST using separate methods, instead of conditional branching in the same function.
  • Leverage multiple inheritances to create reusable view classes.

Defining a class-based view

To display a list of objects, you define a class that inherits from the ListView class. For example, the following defines the TaskList class in the views.py of the todo application:

from django.shortcuts import render
from django.views.generic.list import ListView
from .models import Task

class TaskList(ListView):
    model = Task
    context_object_name = 'tasks'

# ...
   
Code language: Python (python)

The TaskList is a class based-view that inherits from the ListView class. In the TaskList class, we define the following attributes:

  • model specifies the objects from which model you want to display. In this example, we use the Task model. Internally, Django will query all objects from the Task model (Task.objects.all()) and pass it to a template.
  • context_object_name specifies the variable name of the model list in the template. By default, Django uses object_list. However, the name object_list is quite generic. Therefore, we override the context_object_name by setting its value to tasks.

By convention, the TaskList class will load the todo/task_list.html template. The template name follows this convention:

app/model_list.htmlCode language: Python (python)

If you want to set a different name, you can use the template_name attribute. In this tutorial, we’ll use the default template name, which is task_list.html.

Define a route

Change the urls.py of the todo application to the following:

from django.urls import path
from .views import home, TaskList

urlpatterns = [
    path('', home, name='home'),
    path('tasks/', TaskList.as_view(),name='tasks'),
]
Code language: Python (python)

How it works.

First, import the TaskList class from the views.py module.

from .views import home, TaskListCode language: Python (python)

Second, define tasks/ URL that displays the task list:

path('tasks/', TaskList.as_view(),name='tasks'),Code language: Python (python)

In this code, we map the URL tasks/ to the result of the as_view() method of the TaskList class.

Note that you can specify the attributes of the TaskList class in the as_view() method. For example, you can pass a template name to the as_view() method as follows:

path('tasks/', TaskList.as_view(template_name='mytodo.html'),name='tasks'),Code language: Python (python)

The as_view() method has arguments which are corresponding to the attributes of the TaskList class.

Creating a Django ListView template

Define the task_list.html in the templates/blog directory of the Todo app:

{%extends 'base.html'%}

{%block content%}

<div class="center">
	<h2>My Todo List</h2>
	{% if tasks %}
	<ul class="tasks">
		{% for task in tasks %}
			<li><a href="#" class="{% if task.completed%}completed{%endif%}">{{ task.title }}</a> 
				 <div  class="task-controls">
				 	<a href="#"><i class="bi bi-trash"></i> </a>
					<a href="#"><i class="bi bi-pencil-square"></i></a>
		         </div>
		    </li>
		{% endfor %}
	{% else %}
		<p>🎉 Yay, you have no pending tasks!</p>
	{% endif %}
	</ul>
</div>
{%endblock content%}Code language: HTML, XML (xml)

The task_list.html template extends the base.html template of the project. In the task_list.html template, we iterate over the tasks QuerySet and display each of them as an item on a list.

Also, we add the completed CSS class to the a tag if the task is completed. This CSS class will add a line-through to the item.

If the tasks QuerySet is empty, we display a message saying that there are no pending tasks.

Including ListView link in the base template

Modify the base.html template to include the My Tasks link in the navigation:

{%load static %}
<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="{% static 'css/style.css' %}" />
        <title>Todo List</title>
    </head>

    <body>
        <header class="header">
            <div class="container">
            	<a href="{%url 'home'%}" class="logo">Todo</a>
                <nav class="nav">
                	<a href="{%url 'home'%}"><i class="bi bi-house-fill"></i> Home</a>
                	<a href="{% url 'tasks' %}"><i class="bi bi-list-task"></i> My Tasks</a>
                </nav>
            </div>
        </header>
        <main>
            <div class="container">
             {%block content %}
             {%endblock content%}
            </div>
        </main>
        <footer class="footer">
            <div class="container">
               <p>© Copyright {% now "Y" %} by <a href="https://www.shishirkant.com">Python Tutorial</a></p>
            </div>
        </footer>
    </body>

</html>
Code language: HTML, XML (xml)

If you open the URL:

http://128.0.0.1:8000/tasks/Code language: Python (python)

you’ll see the task list as follows:

Summary

  • Create a class-based view that displays a list of objects by inheriting from the ListView class.
]]>
3721
Django Todo App https://shishirkant.com/django-todo-app/?utm_source=rss&utm_medium=rss&utm_campaign=django-todo-app Tue, 18 Apr 2023 08:08:11 +0000 https://shishirkant.com/?p=3715
  • Create a virtual environment
  • Install the Django package
  • Create a new project
  • Adding static files
  • Setting up templates
  • Create the todo app
  • Create the Task model and apply migrations
  • Creating a virtual environment

    Run the following python command to create a virtual environment using the built-in venv module:

    python -m venv venvCode language: plaintext (plaintext)

    And activate the venv virtual environment using the following command:

    venv\scripts\activateCode language: plaintext (plaintext)

    If you use macOS and Linux, you can use the following python3 command to create a new virtual environment:

    python3 -m venv venv

    And activate it using the following command:

    source venv/bin/activateCode language: plaintext (plaintext)

    Install the Django package

    Since Django is a third-party package, you need to install it using the following pip command:

    pip install djangoCode language: plaintext (plaintext)

    Creating a new project

    To create a new project todo_list, you use the startproject command:

    django-admin startproject todo_listCode language: plaintext (plaintext)

    Adding static files

    First, create a static directory inside the project directory:

    mkdir staticCode language: JavaScript (javascript)

    Second, set the STATICFILES_DIRS to the static directory in the settings.py after the STATIC_URL file so that Django can find the static files in the static directory:

    STATIC_URL = 'static/'
    STATICFILES_DIRS = [BASE_DIR / 'static']
    Code language: Python (python)

    Third, create three directories jscss, and images inside the static directory:

    cd static
    mkdir css images jsCode language: JavaScript (javascript)

    The static directory will look like this:

    ├── static
    |  ├── css
    |  ├── images
    |  └── jsCode language: plaintext (plaintext)

    Finally, copy the style.css file and feature.jpg image from the download file to the css and images directories.

    Setting up templates

    First, create a templates directory inside the project directory:

    mkdir templatesCode language: Python (python)

    Second, create a base.html template inside the templates directory with the following contents:

    {%load static %}
    <!DOCTYPE html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <link rel="stylesheet" href="{% static 'css/style.css' %}" />
            <title>Todo List</title>
        </head>
    
        <body>
            <header class="header">
                <div class="container">
                </div>
            </header>
            <main>
                <div class="container">
                </div>
            </main>
            <footer class="footer">
                <div class="container">
                   <p>&copy; Copyright {% now "Y" %} by <a href="https://www.pythontutorial.net">Python Tutorial</a></p>
                </div>
            </footer>
        </body>
    
    </html>Code language: HTML, XML (xml)

    The base.html template uses the style.css file from the static/css directory.

    Third, configure the template directory in the TEMPLATES of the settings.py file so that Django can find the base.html template.

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [BASE_DIR / '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',
                ],
            },
        },
    ]
    Code language: Python (python)

    Fourth, create the home.html template inside the templates directory:

    {%extends 'base.html'%}
    {%load static %}
    {%block content%}
    	<section class="feature">
    		<div class="feature-content">
    			<h1>Todo</h1>
    			<p>Todo helps you more focus, either work or play.</p>	
    			<a class="btn btn-primary cta" href="#">Get Started</a>
    		</div>
    		<img src="{%static 'images/feature.jpg'%}" alt="" class="feature-image">
    	</section>
    {%endblock content%}Code language: JavaScript (javascript)

    Creating a todo application

    First, create a todo app in the todo_list project using the startapp command:

    django-admin startapp todoCode language: Python (python)

    Second, register the todo app in the settings.py of the todo_list project by adding it to the INSTALLED_APPS list:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'todo',
    ]
    Code language: Python (python)

    Third, create the templates directory inside the todo app directory:

    cd todo
    mkdir templatesCode language: Python (python)

    Fourth, create the todo directory inside the templates directory. The directory name must be the same as the app name.

    cd templates
    mkdir todoCode language: Python (python)

    Fifth, define a home() view function inside the views.py of the todo app that renders the home.html template:

    from django.shortcuts import render
    
    def home(request):
        return render(request,'home.html')Code language: Python (python)

    Sixth, create urls.py file in the todo app and define a route that maps to the home URL with the home() view function:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.home, name='home'),
    ]Code language: Python (python)

    Seventh, include the urls.py of the todo app in the urls.py of the project:

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',include('todo.urls'))
    ]
    Code language: Python (python)

    Eighth, run the Django development server from the todo_list directory:

    python manage.py runserverCode language: Python (python)

    Finally, open http://127.0.0.1:8000/ on a web browser, you’ll see the blog page that shows the homepage:

    Create the Task model

    First, define the Task model in the models.py of the todo app:

    from django.db import models
    from django.contrib.auth.models import User
    
    class Task(models.Model):
        title = models.CharField(max_length=255)
        description = models.TextField(null=True, blank=True)
        completed = models.BooleanField(default=False)
        created_at = models.DateTimeField(auto_now_add=True)
        user = models.ForeignKey(User,on_delete=models.CASCADE, null=True, blank=True)
        
        def __str__(self):
            return self.title
        
        class Meta:
            ordering = ['completed']Code language: Python (python)

    Second, register the Task model in the admin.py of the todo app so that you can manage it on the admin page:

    from django.contrib import admin
    
    from .models import Task
    
    admin.site.register(Task)Code language: Python (python)

    Third, make migrations by running the makemigrations command:

    python manage.py makemigrationsCode language: plaintext (plaintext)

    Output:

    Migrations for 'todo':
      todo\migrations\0001_initial.py
        - Create model TaskCode language: plaintext (plaintext)

    Fourth, apply the migrations to the database:

    python manage.py migrateCode language: plaintext (plaintext)

    Output:

    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, sessions, todo
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying admin.0003_logentry_add_action_flag_choices... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying auth.0009_alter_user_last_name_max_length... OK
      Applying auth.0010_alter_group_name_max_length... OK
      Applying auth.0011_update_proxy_permissions... OK
      Applying auth.0012_alter_user_first_name_max_length... OK
      Applying sessions.0001_initial... OK
      Applying todo.0001_initial... OKCode language: plaintext (plaintext)

    Fifth, create a superuser by executing the createsuperuser command:

    python manage.py createsuperuserCode language: plaintext (plaintext)

    Output:

    Username: john
    Email address:
    Password:
    Password (again):
    Superuser created successfully.Code language: plaintext (plaintext)

    Sixth, restart the Django development server:

    python manage.py runserverCode language: plaintext (plaintext)

    Seven, log in to the admin page and create three tasks:

    django todo list - task list

    ]]>
    3715
    Django Login / Logout https://shishirkant.com/django-login-logout/?utm_source=rss&utm_medium=rss&utm_campaign=django-login-logout Tue, 18 Apr 2023 07:59:25 +0000 https://shishirkant.com/?p=3709 Create a new application

    First, create a new application called users by executing the startapp command:

    django-admin startapp users

    The project directory will look like this:

    ├── blog
    ├── db.sqlite3
    ├── manage.py
    ├── mysite
    ├── static
    ├── templates
    └── usersCode language: plaintext (plaintext)

    Second, register the users application in the installed apps of the settings.py of the project:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        # local
        'blog.apps.BlogConfig',
        'users.apps.UsersConfig'
    ]
    Code language: Python (python)

    Third, create a new urls.py file inside the users app with the following code:

    from django.urls import path
    from . import views
    
    urlpatterns = []Code language: Python (python)

    Finally, include the urls.py of the users application in the urls.py of the project by using the include() function:

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',include('blog.urls')),
        path('',include('users.urls'))
    ]
    Code language: Python (python)

    Create a login form

    First, create a login ULR in the urls.py of the users application:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('login/', views.sign_in, name='login'),
    ]Code language: Python (python)

    Second, create a forms.py file in the users application and define the LoginForm that inherits from the Form class:

    from django import forms
    
    
    class LoginForm(forms.Form):
        username = forms.CharField(max_length=65)
        password = forms.CharField(max_length=65, widget=forms.PasswordInput)
    Code language: Python (python)

    The LoginForm has two fields username and password.

    Third, create the sign_in() function in the views.py file of the users application to render the login.html template:

    from django.shortcuts import render
    from .forms import LoginForm
    
    
    def sign_in(request):
        if request.method == 'GET':
            form = LoginForm()
            return render(request, 'users/login.html', {'form': form})
    Code language: Python (python)

    Fourth, create the templates/users directory inside the users application:

    mkdir templates
    cd templates
    mkdir usersCode language: plaintext (plaintext)

    Fifth, create the login.html template inside the templates/users directory that extends the base.html template:

    {% extends 'base.html' %}
    
    {% block content %}
    <form method="POST" novalidate>
    	{% csrf_token %}
    	<h2>Login</h2>
    	{{form.as_p}}
    	<input type="submit" value="Login" />
    </form>
    
    {% endblock content%}Code language: HTML, XML (xml)

    Sixth, open the login URL, and you’ll see the login form:

    http://127.0.0.1:8000/loginCode language: plaintext (plaintext)

    If you enter a username/password and click the Login button, you’ll get an error because we haven’t added the code that handles the HTTP POST request yet.

    Seventh, modify the sign_in() function to handle the login process:

    from django.shortcuts import render, redirect
    from django.contrib import messages
    from django.contrib.auth import login, authenticate
    from .forms import LoginForm
    
    
    def sign_in(request):
    
        if request.method == 'GET':
            form = LoginForm()
            return render(request,'users/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']
                user = authenticate(request,username=username,password=password)
                if user:
                    login(request, user)
                    messages.success(request,f'Hi {username.title()}, welcome back!')
                    return redirect('posts')
            
            # form is not valid or user is not authenticated
            messages.error(request,f'Invalid username or password')
            return render(request,'users/login.html',{'form': form})
    Code language: Python (python)

    How it works.

    First, import the authenticate and login function from the django.contrib.auth module:

    from django.contrib.auth import login, authenticateCode language: Python (python)

    The authenticate() function verifies a username and password. If the username and password are valid, it returns an instance of User class or None otherwise.

    The login() function logs a user in. Technically, it creates a session id on the server and sends it back to the web browser in the form of a cookie.

    In the subsequent request, the web browser sends the session id back to the web server, Django matches the cookie value with the session id and creates the User object.

    Second, verify the username and password using the authenticate() function if the form is valid:

    user = authenticate(request, username=username, password=password)Code language: Python (python)

    Third, log the user in, create a flash message, and redirect the user to the posts URL if the username and password are valid:

    if user:
       login(request, user)
       messages.success(request,f'Hi {user.username.title()}, welcome back!')
       return redirect('posts')Code language: Python (python)

    Otherwise, create a flash error message and redirect the user back to the login page:

    messages.error(request,f'Invalid username or password')
    return render(request,'users/login.html')Code language: Python (python)

    If you enter a username without a password and click the Login button, you’ll get the following error message:

    However, if you enter the correct username/password, you’ll be redirected to the post list page with a welcome message:

    Add a Logout form

    First, define a route for logging a user out:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('login/', views.sign_in, name='login'),
        path('logout/', views.sign_out, name='logout'),
    ]Code language: JavaScript (javascript)

    Second, define the sign_out() function in the views.py file that handles the logout route:

    from django.shortcuts import render, redirect
    from django.contrib import messages
    from django.contrib.auth import login, authenticate, logout
    from .forms import LoginForm
    
    def sign_in(request):
    
        if request.method == 'GET':
            form = LoginForm()
            return render(request,'users/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']
                user = authenticate(request,username=username,password=password)
                if user:
                    login(request, user)
                    messages.success(request,f'Hi {username.title()}, welcome back!')
                    return redirect('posts')
            
            # either form not valid or user is not authenticated
            messages.error(request,f'Invalid username or password')
            return render(request,'users/login.html',{'form': form})
        
        
            
    def sign_out(request):
        logout(request)
        messages.success(request,f'You have been logged out.')
        return redirect('login')        
    Code language: Python (python)

    If you log in and access the login page, you’ll still see the login form. Therefore, it’s better to redirect the logged user to the post list instead if the user accesses the login page.

    Third, modify the sign_in() function in the views.py of the users application:

    def sign_in(request):
    
        if request.method == 'GET':
            if request.user.is_authenticated:
                return redirect('posts')
            
            form = LoginForm()
            return render(request,'users/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']
                user = authenticate(request,username=username,password=password)
                if user:
                    login(request, user)
                    messages.success(request,f'Hi {username.title()}, welcome back!')
                    return redirect('posts')
            
            # either form not valid or user is not authenticated
            messages.error(request,f'Invalid username or password')
            return render(request,'users/login.html',{'form': form})
    Code language: PHP (php)

    The the request.user.is_authenticated returns True if a user is logged in or False otherwise.

    Fourth, modify the base.html template to include the logout link if the user is authenticated and the login link otherwise:

    {%load static %}
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="{% static 'css/style.css' %}" />
        <script src="{% static 'js/app.js' %}" defer></script>
        <title>My Site</title>
      </head>
      <body>
      	<header>
      		{%if request.user.is_authenticated %}
      			<span>Hi {{ request.user.username | title }}</span>
      			<a href="{% url 'logout' %}">Logout</a>
      		{%else%}
      			<a href="{% url 'login' %}">Login</a>
      		{%endif%}
      	</header>
      	<main>
    	  	{% if messages %}
    			<div class="messages">
    			{% for message in messages %}
    				<div class="alert {% if message.tags %}alert-{{ message.tags }}"{% endif %}>
    					{{ message }}
    				</div>
    			{% endfor %}
    			</div>
    		{% endif %}
    		    
    	    {%block content%} 
    	    {%endblock content%}
      	</main>
    	
      </body>
    </html>Code language: HTML, XML (xml)

    If you access the site, you’ll see the login link:

    When you click the login link, it’ll open the login page:

    If you enter the valid username and password and log in, you’ll see a welcome message as well as the logout link:

    If you click the logout link, it redirects to the login page:

    Hiding the edit and delete links on the post list

    If a user is logged in, the request.user.is_authenticated is True. Therefore, you can use this object to show and hide elements of the page whether the user is logged in or not.

    For example, the following hides the editing and deleting links on the blog/home.html template if the user is authenticated:

    {% extends 'base.html' %}
    	
    {% block content %}
    <h1>My Posts</h1>
    	{% for post in posts %}
    		<h2>{{ post.title }}</h2>
    		<small>Published on {{ post.published_at | date:"M d, Y" }} by {{ post.author | title}}</small>
    		<p>{{ post.content }}</p>
    		
    		{% if request.user.is_authenticated %}
    		<p>
    			<a href="{% url 'post-edit' post.id %}">Edit</a> 
    			<a href="{% url 'post-delete' post.id%}">Delete</a>
    		</p>
    		{% endif %}
    		
    	{% endfor %}
    {% endblock content %}
    Code language: HTML, XML (xml)

    Protecting the protected pages

    Typically, you should allow authenticated users to access the creating, updating, and deleting post pages. To do that you can use Django’s login_required decorator.

    If a view function has the login_required decorator and an unauthenticated user attempt to run it, Django will redirect the user to the login page.

    We’ll protect the create, update, and delete post functions using the login_required decorator.

    First, set the login URL in the settings.py of to the login URL:

    LOGIN_URL = 'login'Code language: JavaScript (javascript)

    If you don’t do this, Django will redirect to the default login URL which is accounts/login/ not users/login as we defined in this project.

    Second, modify the views.py of the blog application by adding the @login_required decorator to the create_postedit_post, and delete_post functions:

    from django.shortcuts import render, redirect, get_object_or_404
    from django.contrib import messages
    from django.contrib.auth.decorators import login_required
    from .models import Post
    from .forms import PostForm
    
    
    @login_required
    def delete_post(request, id):
        post = get_object_or_404(Post, pk=id)
        context = {'post': post}
    
        if request.method == 'GET':
            return render(request, 'blog/post_confirm_delete.html', context)
        elif request.method == 'POST':
            post.delete()
            messages.success(request,  'The post has been deleted successfully.')
            return redirect('posts')
    
    
    @login_required
    def edit_post(request, id):
        post = get_object_or_404(Post, id=id)
    
        if request.method == 'GET':
            context = {'form': PostForm(instance=post), 'id': id}
            return render(request, 'blog/post_form.html', context)
    
        elif request.method == 'POST':
            form = PostForm(request.POST, instance=post)
            if form.is_valid():
                form.save()
                messages.success(
                    request, 'The post has been updated successfully.')
                return redirect('posts')
            else:
                messages.error(request, 'Please correct the following errors:')
                return render(request, 'blog/post_form.html', {'form': form})
    
    
    @login_required
    def create_post(request):
        if request.method == 'GET':
            context = {'form': PostForm()}
            return render(request, 'blog/post_form.html', context)
        elif request.method == 'POST':
            form = PostForm(request.POST)
            if form.is_valid():
                form.save()
                messages.success(
                    request, 'The post has been created successfully.')
                return redirect('posts')
            else:
                messages.error(request, 'Please correct the following errors:')
                return render(request, 'blog/post_form.html', {'form': form})
    
    
    def home(request):
        posts = Post.objects.all()
        context = {'posts': posts}
        return render(request, 'blog/home.html', context)
    
    
    def about(request):
        return render(request, 'blog/about.html')
    
    Code language: JavaScript (javascript)

    If you open the create, update, or delete URL, for example:

    http://127.0.0.1/post/createCode language: JavaScript (javascript)

    It’ll be redirected to the login page.

    Summary

    • Use authenticate() function to verify a user by username and password.
    • Use login() function to log a user in.
    • Use logout() function to log a user out.
    • Use request.user.is_authenticated to check if the current user is authenticated.
    • User @login_required decorator to protect pages from unauthenticated users.
    ]]>
    3709
    Django Delete Form https://shishirkant.com/django-delete-form/?utm_source=rss&utm_medium=rss&utm_campaign=django-delete-form Tue, 18 Apr 2023 07:56:49 +0000 https://shishirkant.com/?p=3705 We’ll create a form that deletes a post by its id.

    Creating an URL pattern

    Add an URL pattern to the pattern list in the urls.py of the blog application:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.home, name='posts'),
        path('post/create', views.create_post, name='post-create'),
        path('post/edit/<int:id>/', views.edit_post, name='post-edit'),
        path('post/delete/<int:id>/', views.delete_post, name='post-delete'),
        path('about/', views.about, name='about'),
    ]
    Code language: Python (python)

    The delete URL accepts an id as an integer that specifies the id of the post to be deleted. When you open the URL:

    http://127.0.0.1/post/delete/1/Code language: Python (python)

    Django will execute the delete_post() function in the views.py.

    Defining a view function

    Define a delete_post() function in the views.py of the blog application:

    from django.shortcuts import render,redirect, get_object_or_404
    from django.contrib import messages
    from .models import Post
    from .forms import PostForm
    
    
    def delete_post(request, id):
        post = get_object_or_404(Post, pk=id)
        context = {'post': post}    
        
        if request.method == 'GET':
            return render(request, 'blog/post_confirm_delete.html',context)
        elif request.method == 'POST':
            post.delete()
            messages.success(request,  'The post has been deleted successfully.')
            return redirect('posts')
    
    # ...Code language: Python (python)

    How it works.

    • First, get the post by id using the get_object_or_404() and render the post_confirm_delete.html template. If the post doesn’t exist, then redirects to a 404 page.
    • Second, render the post_confirm_delete.html template if the HTTP request is GET.
    • Third, delete the post, create a flash message, and redirect to the post list if the HTTP request is POST.

    Creating a template

    Create the post_confirm_delete.html template in the templates/blog directory of the blog application. This template extends the base.html template of the project:

    {% extends 'base.html' %} 
    
    {% block content %}
    <h2>Delete Post</h2>
    
    <form method="POST">
      {% csrf_token %}
      <p>Are you sure that you want to delete the post "{{post.title}}"?</p>
      <div>
        <button type="submit">Yes, Delete</button>
        <a href="{% url 'posts' %}">Cancel</a>
      </div>
    </form>
    
    {% endblock content %}Code language: HTML, XML (xml)

    This template contains a form that has two buttons. If you click the submit button (Yes, Delete) it’ll send an HTTP POST request to the specified URL. Otherwise, it’ll navigate to the post list URL.

    Adding the delete link to the post

    Add the delete link to each post in the home.html template:

    {% extends 'base.html' %}
    	
    {% block content %}
    <h1>My Posts</h1>
    	{% for post in posts %}
    		<h2>{{ post.title }}</h2>
    		<small>Published on {{ post.published_at | date:"M d, Y" }} by {{ post.author | title}}</small>
    		<p>{{ post.content }}</p>
    		<p>
    			<a href="{% url 'post-edit' post.id %}">Edit</a> 
    			<a href="{% url 'post-delete' post.id%}">Delete</a>
    		</p>
    	{% endfor %}
    {% endblock content %}
    Code language: HTML, XML (xml)

    If you open the URL http://127.0.0.1/, you’ll see the delete link that appears next to the edit link:

    If you click the delete link, you’ll navigate to the delete URL. For example, the following shows the page when deleting the post with the title "Flat is better than nested***":

    Once you click the Yes, Delete button, Django will execute the delete_post() function that deletes the post and redirects you to the post list:

    Summary

    • Use the delete() method to delete a model from the database.
    ]]>
    3705
    Django Edit Form https://shishirkant.com/django-edit-form/?utm_source=rss&utm_medium=rss&utm_campaign=django-edit-form Tue, 18 Apr 2023 07:53:11 +0000 https://shishirkant.com/?p=3700 We’ll create a Django Edit Form that updates a blog post and saves the changes into the database.

    Create an URL pattern

    First, create a URL pattern for editing a post:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.home, name='posts'),
        path('post/create', views.create_post, name='post-create'),
        path('post/edit/<int:id>/', views.edit_post, name='post-edit'),
        path('about/', views.about, name='about'),
    ]
    Code language: Python (python)

    The editing post URL accepts an id as an integer specified by the <int:id> pattern. For example, if you edit the post with id 1, the URL will be:

    http://127.0.0.1/post/update/1/Code language: Python (python)

    Django will pass the id (1) to the second argument to the edit_post() function.

    If you pass a value that is not an integer to the URL like this:

    http://127.0.0.1/post/update/abcd/Code language: Python (python)

    Django will redirect to 404 because it doesn’t match any URL in the URL patterns.

    Define a view function

    Define the edit_post() function in the views.py file:

    from django.shortcuts import render,redirect, get_object_or_404
    from django.contrib import messages
    from .models import Post
    from .forms import PostForm
    
        
    def edit_post(request, id):
        post = get_object_or_404(Post, id=id)
    
        if request.method == 'GET':
            context = {'form': PostForm(instance=post), 'id': id}
            return render(request,'blog/post_form.html',context)
    
    # other functions
    Code language: Python (python)

    How it works:

    First, import get_object_or_404 function from the django.shortcuts module:

    from django.shortcuts import render,redirect, get_object_or_404Code language: Python (python)

    The get_object_or_404() function gets an object by id or redirects to the 404 page if the id doesn’t exist.

    Second, define the edit_post() function that accepts an HttpRequest object (request) and an id as an integer.

    The edit_post() function does the following steps:

    • Get a Post object by id or redirect to the 404 page if the id doesn’t exist.
    • Create a PostForm object and set the instance argument to the post object.
    • Render the post_form.html template.

    Third, modify the post_form.html template to change the heading of the form. Currently, it shows Create Post.

    {% extends 'base.html' %}
    	
    {% block content %}
    
    <h2>{% if id %} Edit {% else %} New {% endif %} Post</h2>
    <form method="post" novalidate>
    	{% csrf_token %}
    	{{ form.as_p }}
    	<input type="submit" value="Save" />
    </form>
    
    {% endblock content %}
    Code language: HTML, XML (xml)

    If the id (post id) is available, then the form is in edit mode. Otherwise, it is in the creation mode. Based on this logic, we change the heading of the form accordingly.

    Fourth, modify the home.html template to include the edit link in each post:

    {% extends 'base.html' %}
    	
    {% block content %}
    <h1>My Posts</h1>
    	{% for post in posts %}
    		<h2>{{ post.title }}</h2>
    		<small>Published on {{ post.published_at | date:"M d, Y" }} by {{ post.author | title}}</small>
    		<p>{{ post.content }}</p>
    		<p><a href="{% url 'post-edit' post.id %}">Edit</a></p>
    	{% endfor %}
    {% endblock content %}
    Code language: HTML, XML (xml)

    Fifth, open the post list URL http://127.0.0.1/, you’ll see a list of posts with the edit link on each as shown in the following picture:

    django edit form - add edit link

    If you click the Edit link to edit a post, you’ll see a form populated with field values. For example, you can edit the post “Flat is better than nested”, you’ll see the following form:

    To edit the post, you change the values and click the Save button. However, we haven’t added the code that handles the HTTP POST request yet.

    Sixth, add the code that handles the HTTP POST request i.e. when the Save button is clicked:

    def edit_post(request, id):
        post = get_object_or_404(Post, id=id)
    
        if request.method == 'GET':
            context = {'form': PostForm(instance=post), 'id': id}
            return render(request,'blog/post_form.html',context)
        
        elif request.method == 'POST':
            form = PostForm(request.POST, instance=post)
            if form.is_valid():
                form.save()
                messages.success(request, 'The post has been updated successfully.')
                return redirect('posts')
            else:
                messages.error(request, 'Please correct the following errors:')
                return render(request,'blog/post_form.html',{'form':form})
    Code language: Python (python)

    Update the post by appending three asterisks (***) to the title:

    Click the Save button and you’ll see that the post will be updated:

    Summary

    • Include <int:id> pattern in a URL to create an editing URL that accepts a model id as an integer.
    • Use the get_object_or_404() function to get an object by id or redirect to the 404 page if the object doesn’t exist.
    • Pass a model instance to a model form to render the model fields.
    ]]>
    3700
    Django Flash Messages https://shishirkant.com/django-flash-messages/?utm_source=rss&utm_medium=rss&utm_campaign=django-flash-messages Tue, 18 Apr 2023 07:51:23 +0000 https://shishirkant.com/?p=3696 Introduction to the Django Flash Messages

    A flash message is a one-time notification message. To display the flash message in Django, you use the messages from django.contrib module:

    from django.contrib import messagesCode language: Python (python)

    The messages have some useful functions for displaying information, warning, and error messages:

    • messages.debug – displays a debug message.
    • messages.info – displays an informational message.
    • messages.success – displays a success message.
    • messages.warning – displays a warning message.
    • messages.error – displays an error message.

    All of these functions accept an HttpRequest object as the first argument and a message as the second argument.

    Django Flash message example

    We’ll implement flash messages for the blog app in the django_project.

    Creating Django flash messages

    Modify the create_post() function by adding the flash messages:

    from django.shortcuts import render,redirect
    from django.contrib import messages
    from .models import Post
    from .forms import PostForm
    
    
    def create_post(request):
        if request.method == 'GET':
            context = {'form': PostForm()}
            return render(request,'blog/post_form.html',context)
        elif request.method == 'POST':
            form = PostForm(request.POST)
            if form.is_valid():
                form.save()
                messages.success(request, 'The post has been created successfully.')
                return redirect('posts')
            else:
                messages.error(request, 'Please correct the following errors:')
                return render(request,'blog/post_form.html',{'form':form})
    Code language: Python (python)

    How it works.

    First, import messages from the django.contrib:

    from django.contrib import messagesCode language: Python (python)

    Second, create a success message after saving the form values into the database by calling the success() function:

    messages.success(request, 'The post has been created successfully.')Code language: Python (python)

    Third, create an error message if the form is not valid by calling the error() function:

    messages.error(request, 'Please correct the following errors:')Code language: Python (python)

    Displaying flash messages

    Modify the base.html template to display flash messages:

    {%load static %}
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="{% static 'css/style.css' %}" />
        <script src="{% static 'js/app.js' %}" defer></script>
        <title>My Site</title>
      </head>
      <body>
    	{% if messages %}
    		<div class="messages">
    		{% for message in messages %}
    			<div class="alert {% if message.tags %}alert-{{ message.tags }}"{% endif %}>
    				{{ message }}
    			</div>
    		{% endfor %}
    		</div>
    	{% endif %}
    	    
        {%block content%} 
        {%endblock content%}
      </body>
    </html>
    Code language: HTML, XML (xml)

    If you navigate to the form http://127.0.0.1/post/create, enter the values, and click the Save button:

    … you’ll see a success message:

    If you refresh the page, the message will disappear because it displays only once.

    When you skip entering a value for the title field and click the Save button:

    django flash messages - invalid form

    … you’ll see an error message:

    django flash messages - error message

    Summary

    • Use the messages from django.contrib to create and display messages.
    ]]>
    3696
    Django Form https://shishirkant.com/django-form/?utm_source=rss&utm_medium=rss&utm_campaign=django-form Tue, 18 Apr 2023 07:49:24 +0000 https://shishirkant.com/?p=3688 Django admin is good enough for admin to manage the contents based on the models. However, when you want the users of the website to manage their content, you need to create separate forms for them.

    Introduction to the Django Form

    Handling forms involves very complex logic:

    • Prepare an HTML form.
    • Validate fields in the browser using JavaScript or built-in HTML5 validation.
    • Receive the values in the server.
    • Validate fields in the server.
    • Processing form values like saving them into the database if the form is valid
    • Rerender the form with old values and an error message if the form is invalid.

    Django forms simplify and automate almost all of the above steps.

    Note that you can write code to do all of the above steps manually if you want more customization of the forms.

    All forms in Django inherit from the django.forms.Form class. The ModelForm class allows you to create a form that associates with a model .

    Defining a form

    First, create a new file forms.py in the blog application’s directory.

    Second, define a new form called PostForm that inherits from the ModelForm class:

    from django.forms import ModelForm
    from .models import Post
    
    class PostForm(ModelForm):
        class Meta:
            model = Post
            fields = ['title','content', 'author', 'author']       Code language: Python (python)

    How it works.

    • Import ModelForm from the django.forms.
    • Import Post from the models.py module.
    • Define PostForm class that inherits from the ModelForm class. In the PostForm class, define the Meta class and specify the model and fields attributes.

    Third, define a route that displays the PostForm:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.home, name='posts'),
        path('post/create', views.create_post, name='post-create'),
        path('about/', views.about, name='about'),
    ]
    Code language: Python (python)

    Fourth, define create_post() function that displays the form:

    from django.shortcuts import render
    from .models import Post
    from .forms import PostForm
    
    
    def create_post(request):
        if request.method == 'GET':
            context = {'form': PostForm()}
            return render(request, 'blog/post_form.html', context)
    
    
    def home(request):
        posts = Post.objects.all()
        context = {'posts': posts}
        return render(request, 'blog/home.html', context)
    
    
    def about(request):
        return render(request, 'blog/about.html')Code language: Python (python)

    In the create_post(), if the HTTP request is GET, then create a new instance of the PostForm class and pass it to the render() function.

    Fifth, create the post_form.html template:

    {% extends 'base.html' %}
    	
    {% block content %}
    
    <h2>New Post</h2>
    <form method="post" novalidate>
    	{% csrf_token %}
    	{{ form.as_p }}
    	<input type="submit" value="Save" />
    </form>
    
    {% endblock content %}Code language: HTML, XML (xml)

    In the post_form.html, add the csrf_token tag and render the form using the form.as_p property. It’ll output the following:

    <p>
        <label for="id_title">Title:</label>
        <input type="text" name="title" maxlength="120" required id="id_title">
    </p>
    <p>
        <label for="id_content">Content:</label>
        <textarea name="content" cols="40" rows="10" required id="id_content"></textarea>
    </p>Code language: HTML, XML (xml)

    If you open the URL http://127.0.0.1:8000/post/create, you’ll see the following form:

    If you click the Save button, you’ll see the error message:

    Because the title, content, and author fields of the Post model are required fields by default, the PostForm that uses the Post model also renders an HTML form that requires these fields.

    To test the server validation, you can disable the client validation by adding the novalidate property to the form like this:

    {% extends 'base.html' %}
    	
    {% block content %}
    
    <h2>New Post</h2>
    <form method="post" novalidate>
    	{% csrf_token %}
    	{{ form.as_p }}
    	<input type="submit" value="Save" />
    </form>
    
    {% endblock content %}Code language: HTML, XML (xml)

    To handle the HTTP POST method, you need to modify the create_post function in the views.py of the blog application:

    from django.shortcuts import render, redirect
    from .models import Post
    from .forms import PostForm
    
    
    def create_post(request):
        if request.method == 'GET':
            context = {'form': PostForm()}
            return render(request, 'blog/post_form.html', context)
        elif request.method == 'POST':
            form = PostForm(request.POST)
            if form.is_valid():
                form.save()
                return redirect('posts')
            else:
                return render(request, 'blog/post_form.html', {'form': form})
    
    # ...Code language: Python (python)

    If the HTTP request is POST (request.method==’POST‘):

    • Create a new instance of the PostForm class with the data from the POST.
    • Check if the form is valid.
    • If the form is valid, save the form values into the database and redirect the web browser to the 'posts' path.
    • Otherwise, rerender the form with old values and errors.

    If you submit the form without entering anything values, you’ll get the following error messages:

    However, when you provide values for some required fields, Django renders the form with old values and displays error messages for only invalid fields.

    For example, the following form displays the error message for the title field while retaining the old values for the content and author fields:

    If you enter valid values for all the fields, Django saves the values into the database

    …and redirect to the post list:

    Summary

    • Create a model form by subclassing the ModelForm.
    • Add the novalidate property to the form to disable HTML5 validation temporarily for testing server validation.
    • Use form.is_valid() to check if the form is valid.
    • Use form.save() to save form values into the database.
    • Use redirect() to redirect to a path.
    ]]>
    3688