I/ Tổng quan về Django

Python được biết đến như một ngôn ngữ lập trình với sự tiện lợi và đa năng. Ngoài việc được sử dụng để phát triển AI vì có số lượng thư viện hỗ trợ khổng lồ, thì Python còn được sử dụng trong các mảng như lập trình game, web, script, hacking, embedded,... Trong lĩnh vực lập trình web, Python khá nổi tiếng với framework Django vì được nhiều công ty lớn sử dụng.

Django là một Web Framework cao cấp được viết bằng ngôn ngữ Python, khuyến khích việc phát triển website một cách nhanh chóng và gọn gàng. Được xây dựng bởi các nhà phát triển có kinh nghiệm, nó xử lý rất nhiều rắc rối của việc phát triển web, vì vậy bạn có thể tập trung vào việc viết ứng dụng của mình mà không cần phải đi phát minh lại bánh xe. Ngoài ra đây còn là một open source framework.

II/ Cài đặt Django

Hãy chắc chắn rằng trên máy của bạn đã cài đăt sẵn Python3 và pip tương ứng. Đối với hệ điều hành thuộc linux hoặc debian thường sẽ được cài đặt sẵn Python3 và pip3. Bạn có thể download Python3 cho Windows tại đây.

Tiến hành cài đặt Django sử dụng pip

  • Trên hệ điều hành Ubuntu
$ sudo pip3 install django #download package django
$ django-admin --version #check django version
  • Trên hệ điều hành Windows
...\> pip install django #download package django
...\> django-admin --version #check django version

III/ Tìm hiểu về kiến trúc của Django và cách khởi tạo dự án

1/ Kiến trúc của django

Không như những framework khác, django sử dụng mô hình MVT(Model-View-Template) thay vì sử mô hình MVC(Model-View-Controller).

Bạn có thể tìm hiểu thêm về sự khác nhau giữa mô hình MVT và MVC tại đây.

  • Model trong MVT tương tự như trong MVC, là nơi chứa những nghiệp vụ tương tác với dữ liệu hoặc hệ quản trị cơ sở dữ liệu (mysql, mssql… ); nó sẽ bao gồm các class/function xử lý nhiều nghiệp vụ như kết nối database, truy vấn dữ liệu, thêm – xóa – sửa dữ liệu…
  • View thực thi các logic nghiệp vụ, tương tác với Model và render ra các Template. Nó chấp nhận yêu cầu HTTP và sau đó trả về các phản hồi HTTP, quyết định dữ liệu nào sẽ được hiển thị.
  • Template là thành phần làm cho MVT khác với MVC. Template đóng vai trò là presentation layer và về cơ bản là code HTML hiển thị dữ liệu. Nội dung trong các tệp này có thể là tĩnh hoặc động. Nó xác định cách trình bày dữ liệu.

2/ Khởi tạo một dự án:

Để mọi người có một cái nhìn tổng quát về cách thức hoạt động và kiến trúc của Django, mình sẽ setup một todo app sử dụng Django thuần.

Khởi tạo một project có tên todo

$ django-admin startproject todo

Việc thực hiện startproject đóng vai trò như việc khởi tạo một môi trường nền cho các ứng dụng có thể được xây dựng trên môi trường này.

Sau khi thực thi, nó sẽ tạo một directory có tên todo ở đường dẫn hiện tại. Và có cấu trúc như sau:

todo/
    manage.py
    todo/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

Trong đó:

  • todo/ ngoài cùng là một container cho project của chúng ta. Tên này không quan trọng trong Django, có thể rename nếu muốn.
  • manage.py là một tiện ích command-line cho phép bạn tương tác với dự án Django này theo nhiều cách khác nhau.
  • todo/ là một thư mục chứa các Python package cho project của chúng ta.
  • __init__.py  nói với trình thông dịch python là thư mục nên được coi là một python package. Tập tin này chủ yếu là trống.
  • urls.py Bao gồm tất cả khai báo URL cho dự án Django và mục lục của trang web Django.
  • wsgi.py Đây là lối vào cho các máy chủ web tương thích WSGI để phục vụ các dự án của bạn và deploy với WSGI.

Deploy server

$ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
September 07, 2022 - 01:43:00
Django version 3.1, using settings 'todo.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Theo mặc định, lệnh runserver khởi động development server trên local IP tại cổng 8000. Bây giờ project server của chúng ta đã được khởi động và chạy ở địa chỉ http://127.0.0.1:8000/

Khi truy cập vào http://127.0.0.1:8000/ ta sẽ được kết quả như sau:

Như vậy là chúng ta đã tạo dựng được một môi trường sẵn sàng cho việc xây dựng các ứng dụng.

Tiếp theo ta sẽ khởi tạo một app có tên tasks

Mỗi ứng dụng bạn viết trong Django bao gồm một Python package tuân theo một quy ước nhất định. Django đi kèm với một tiện ích tự động tạo cấu trúc thư mục cơ bản của một ứng dụng, vì vậy bạn có thể tập trung vào việc viết mã thay vì tạo thư mục.

projects vs. apps

Sự khác biệt giữa dự án và một ứng dụng là gì? Một ứng dụng là một ứng dụng web thực hiện một cái gì đó - ví dụ: hệ thống blog, cơ sở dữ liệu hồ sơ công cộng hoặc một ứng dụng thăm dò ý kiến nhỏ. Một dự án là một tập hợp các cấu hình và ứng dụng cho một trang web cụ thể. Một dự án có thể chứa nhiều ứng dụng. Một ứng dụng có thể có trong nhiều dự án.
$ python manage.py startapp tasks

app vừa tạo có cấu trúc thư mục như sau:

tasks/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

Để có thể đưa app vừa tạo vào project, ta cần config todo\todo\settings.py  

# todo\todo\settings.py
INSTALLED_APPS = [
    ...
    ...
    
    'tasks',
]

Sau khi đã thêm app vào project, ta tiếp tục tạo model cho app của chúng ta

# todo\tasks\models.py

from django.db import models

# Create your models here.

class Task(models.Model):
	title = models.CharField(max_length=200)
	complete = models.BooleanField(default=False)
	created = models.DateTimeField(auto_now_add=True)

	def __str__(self):
		return self.title

Để sử dụng form từ model đã tạo, chúng ta sẽ tạo file ở đường dẫn todo\tasks\forms.py

Chúng ta sẽ import model Task đã tạo và sẽ sử dụng tất cả các trường của model này.

# todo\tasks\forms.py

from django import forms
from django.forms import ModelForm

from .models import *

class TaskForm(forms.ModelForm):
	title= forms.CharField(widget= forms.TextInput(attrs={'placeholder':'Add new task...'}))

	class Meta:
		model = Task
		fields = '__all__'

Để có thể tạo ra table từ model, ta dùng lệnh makemigrations để apply các thay đổi ở  file models.py và lệnh migrate để apply trực tiếp vào database.

Sự tiện lợi của Django là ở chỗ chúng ta không cần phải trực tiếp thiết lập kết nối đến database (mysql, pgsql,...), mà mặc định ở file settings.py đã thiết lập sẵn một kết nối đến built-in sqlite, tất cả table và data đã tạo sẽ được lưu ở file db.sqlite3. Tất nhiên là chúng ta vẫn có thể thiết lập kết nối đến database mà chúng ta muốn.

# todo\todo\settings.py

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
$ python3 manage.py makemigrations
Migrations for 'tasks':
  tasks\migrations\0001_initial.py
    - Create model Task

$ python3 manage.py migrate       
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, tasks
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 tasks.0001_initial... OK

Sau đó, ta tiếp tục triển khai phần views của ứng dụng, Như đã nói ban đầu, view của Django quyết định các dữ liệu được trả về và điều hướng các request http của ứng dụng.

# todo\tasks\views.py 
from django.shortcuts import render, redirect
from django.http import HttpResponse

from .models import *
from .forms import *

# Create your views here.

def index(request):
	tasks = Task.objects.all()

	form = TaskForm()

	if request.method =='POST':
		form = TaskForm(request.POST)
		if form.is_valid():
			form.save()
		return redirect('/')


	context = {'tasks':tasks, 'form':form}
	return render(request, 'tasks/list.html', context)

def updateTask(request, pk):
	task = Task.objects.get(id=pk)

	form = TaskForm(instance=task)

	if request.method == 'POST':
		form = TaskForm(request.POST, instance=task)
		if form.is_valid():
			form.save()
			return redirect('/')

	context = {'form':form}

	return render(request, 'tasks/update_task.html', context)

def deleteTask(request, pk):
	item = Task.objects.get(id=pk)

	if request.method == 'POST':
		item.delete()
		return redirect('/')

	context = {'item':item}
	return render(request, 'tasks/delete.html', context)

Sau khi đã có model và view, việc còn lại cần làm là phải tạo route(url) và template cho ứng dụng để người dùng có thể truy cập vào ứng dụng của chúng ta

Trước tiên chúng ta cần điều hướng để những request đến url mặc định '/' từ todo\todo\urls.py sẽ được đưa đến todo\tasks\urls.py thông qua việc include path path('', include('tasks.urls'))

# todo\todo\urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('tasks.urls'))
]
# todo\tasks\urls.py

from django.urls import path
from . import views

urlpatterns = [
	path('', views.index, name="list"),
	path('update_task/<str:pk>/', views.updateTask, name="update_task"),
	path('delete/<str:pk>/', views.deleteTask, name="delete"),
]

Để có người dùng có thể request đến đúng tác vụ mong muốn thì chúng ta sẽ cần thiết lập các url tương ứng với các functions đã tạo ở file views. (ví dụ: khi người dùng truy cập vào địa chỉ http://127.0.0.1:8000/ thì hàm index sẽ được gọi,..)

Tạo template, trước tiên ta cần tạo các file có cấu trúc thư mục như sau:

tasks/
    templates/
    	tasks/
            delete.html
            list.html
            update_task.html
        
# todo\tasks\templates\tasks\list.html
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<style>

	body{
		background-color: #638CB8;
	}

	input{
		width: 100%;
		padding: 12px 20px;
		margin: 8px 0;
		box-sizing: border-box;
	}

	input::placeholder {
	  color: #d3d3d3;
	}

	.submit{
		background-color: #6BA3E8;
	}

	.center-column{
		width:600px;
		margin: 20px auto;
		padding:20px;
		background-color: #fff;
		border-radius: 3px;
		box-shadow: 6px 2px 30px 0px rgba(0,0,0,0.75);
	}

	.item-row{
		background-color: #906abd;
		margin: 10px;
		padding: 20px;
		border-radius: 3px;
		color: #fff;
		font-size: 16px;
		box-shadow: 0px -1px 10px -4px rgba(0,0,0,0.75);
	}

	.btn-danger{
		background-color: #ffae19;
		border-color: #e59400;
	}

</style>

<div class="center-column">

	<form method="POST" action="/">
		{% csrf_token %}
		{{form.title}}
		<input class="btn btn-info" type="submit" name="Create Task">
	</form>

	<div class="todo-list">

	{% for task in tasks %}
		<div class="item-row">
			<a class="btn btn-sm btn-info" href="{% url 'update_task' task.id %}">Update</a>
			<a class="btn btn-sm btn-danger" href="{% url 'delete' task.id %}">Delete</a>

			{% if task.complete == True %}
			<strike>{{task}}</strike>
			{% else %}
			<span>{{task}}</span>
			{% endif %}
		</div>
	{% endfor %}
	</div>
</div>
# todo\tasks\templates\tasks\delete.html
<p>Are you sure you want to delete "{{item}}"?</p>
<a href="{% url 'list' %}" >Cancel</a>
<form method="POST" action="">
	{% csrf_token %}
	<input type="submit" name="Confirm">
</form>
# todo\tasks\templates\tasks\update_task.html
<h3>Update Task</h3>
<form method="POST" action="">
	{% csrf_token %}
	{{form}}
	<input type="submit" name="Update Task">
</form>

Vì tính bảo mật nên tất cả các form trong django đều sẽ cần có csrf_token

Kết quả ta được như sau:

Danh sách các tasks cần thực hiện

Update task

Xóa task đã tạo

IV/ Tổng kết

Như vậy là chúng ta đã tìm hiểu được khái quát các khái niệm cơ bản về Django và cách khởi tạo một project đơn giản sử dụng Django.

Trong khoảng thời gian còn là sinh viên thực hiện các project ở trường, mình và team của mình đã sử dụng Django cho hầu hết các project và đều mang lại các kết quả, đánh giá tốt. Django là một framework mạnh mẽ nhưng lại có tính dễ tiếp cận. Thực sự có thể xem Django là một trong những framework tốt trên thị trường hiện nay.

V/ Tài liệu tham khảo