Hướng dẫn url build python

Bạn có thể download file (File ảnh, File text, …) từ 1 đường dẫn trên web sử dụng thư viện urllib của Python 3.

Đoạn source code Python 3 như sau:

import urllib
import os

output_dir = '/tmp'
image_url = 'https://vinasupport.com/assets/img/vinasupport_logo.png'

# Make output directory if not exist
if not os.path.exists(output_dir):
    os.makedirs(output_dir)

# save path
image_save_path = output_dir + '/' + os.path.basename(image_url)

# Download file from url
urllib.request.urlretrieve(image, image_save_path)
print(image_save_path)

Trong ví dụ trên, mình thực hiện download file ảnh có đường dẫn là: https://vinasupport.com/assets/img/vinasupport_logo.png

Và lưu nó xuống dường dẫn trên server /tmp/vinasupport_logo.png

Một cách khác là sử dụng thư viện requests

Đầu tiên cài đặt requests thông qua trình quản lý module / packages của Python 3

pip install requests

Sử dụng requests để download file:

from requests import get  # to make GET request

def download(url, file_name):
    # open in binary mode
    with open(file_name, "wb") as file:
        # get request
        response = get(url)
        # write to file
        file.write(response.content)

Nguồn: vinasupport.com

Chúng ta là các lập trình viên, và chúng ta luôn được khuyên là: "Cách nhanh và hiệu quả nhất trong việc học lập trình và bắt tay vào giải quyết các bài toán thực tế". Kinh nghiệm và kiến thức sẽ đến trong quá trình chúng ta giải quyết các bài toán này. Các "bài toán mẫu" hay pet projects/ litte side projects đến từ đâu? Nhiều khi đến từ những ý tưởng nhỏ trong đời sống hoặc đơn giản hơn, chúng ta thực hiện clone lại các ứng dụng đã có để xem các lập trình viên đi trước đã dừng những technique nào để giải quyết nó.

Hôm nay, tôi sẽ cùng các bạn thực hiện xây dựng nhanh một ứng dụng rút gọn link bằng python-django, giống như bitly.com chẳng hạn.

Phân tích bài toán.

Bài toán này nếu viết theo dạng user-story thì không có gì phức tạp, nó sẽ là các dòng yêu cầu như sau:

Tôi là Mr.Bee, tôi là đại diện marketing của công ty X, tôi thường xuyên phải gửi link đến các trang web của công ty cho khách hàng của chúng ta, đường link của chúng ta khá dài, khách hàng khó nhớ. Bản thân tôi đôi lúc cũng cần phải nhớ các đường link để ghi ra giấy sticky-note cho khách hàng. Nếu sử dụng link thu gọn từ một dịch vụ bên ngoài thì không mang lại tin tưởng của khách hàng.

Tôi muốn có một hệ thống rút gọn link có domain của công ty, cho phép tôi thu gọn url thành một chuỗi ngắn, có thể cho phép cá nhân hóa thành tên-số-điện-thoại khách hàng.


Sau khi qua phân tích yêu cầu, story này có thể tóm lại bằng các yêu cầu sau:
1. Đầu vào là 1 link gốc, hệ thống sẽ rút gọn link gốc đó thành 1 dạng link ngắn hơn và duy nhất.
2. Khi người dùng truy cập vào link rút gọn, hệ thống sẽ chuyển nó đến link gốc.
3. Người dùng có thể lựa chọn phần link rút gọn của mình theo ý muốn.

Về mặt kỹ thuật, yêu cầu này có thể giải quyết rất đơn giản bằng cách xây dựng một ứng dụng chỉ với một bảng dữ liệu gồm các trường dữ liệu sau:

alias: kiểu chuỗi, là phần rút gọn sẽ hiển thị cho user
url: Kiểu chuỗi, là link mà user muốn rút gọn.

Khi người dùng thực hiện truy nhập vào link rút gọn, hệ thống sẽ tìm kiếm trong cơ sở dữ liệu và trả về link gốc kèm theo status_code 301 REDIRECT

Tất tần tật về Django

1. Django là gì?

Django là một python-web-framework mã nghuồn mở và miễn phí, cho phép xây dựng nhanh các ứng dụng web dựa trên các khung kiến trúc đã được tối ưu. Django được xây dựng bởi đội ngũ các lập trình viên có nhiều kinh nghiệm đến từ Django Software Foundation(DSF) - một tổ chức phi lợi nhuận. Phần lõi của Django đã thực hiện xử lý những thứ phức tạp của hệ thống phát triển web bằng cách cung cấp các module sẵn có như ORM, Template, Routing,... Các lập trình viên sử dụng django chỉ cần tập trung vào việc phát triển các ứng dụng của mình sao cho nó chạy đúng với yêu cầu của người dùng. Các tài liệu, mô tả về ưu điểm của django, các bạn có thể tìm hiểu thêm từ trang chủ của framework: https://www.djangoproject.com/

Django đã trải qua các lần LTS với nhiều thay đổi như 1.11, 2.2, ... Version hiện tại (tháng 12/2020), của Django là 3.1.x. Với mỗi version đều có các tài liệu, tutorial cho phép các lập trình viên có thể nhanh chóng tìm hiểu và xây dựng cho mình một ứng dụng dạng "blog" đơn giản.

Nếu bạn là một người mới bắt đầu tìm hiểu về Django, hãy bắt đầu từ tài liệu tutorial miễn phí trên trang web của họ: https://docs.djangoproject.com/en/3.1/intro/tutorial01/.

Hoặc bạn có thể bắt đầu bằng bài viết dưới đây của tôi :) Mặc dù nó sẽ không thể chi tiết được như trên tutorial.

2. Cài đặt Django

Để bắt đầu cài đặt Django, chúng ta sẽ thực hiện việc cài đặt một virtual environment (tham khảo từ bài viết: Làm Chủ Python Virtual Environment - Môi Trường Lập Trình Ảo ? )

Thực hiện install Django thông qua trình quản lý package pip:

pip install django

Việc cài đặt có thể kéo dài trong một vài phút, tùy thuộc vào đường truyền mạng của chúng ta.

Sau khi thực hiện cài đặt xong, chúng ta kiểm tra lại xem việc cài đặt đã thành công chưa bằng câu lệnh:

(django3_venv)> pip freeze
asgiref==3.3.1
Django==3.1.4
pytz==2020.4
sqlparse==0.4.1

3. Khởi tạo website với django

Bây giờ chúng ta sẽ bắt đầu thực hiện cài đặt website cho mình.
Sau khi cài đặt xong django, chúng ta sẽ có một công cụ sử dụng trên command-line có tên là django-admin, công cụ này cho phép chúng ta thực hiện việc khởi tạo các website, application, migrate, shell, dbshell, ...

Để tạo ra một project, chúng ta dùng command:

django-admin startproject my_url

Chúng ta sẽ có một thư mục my_url bên trong chứa cấu trúc như bên dưới:

my_url
│   manage.py
│
└───my_url
        asgi.py
        settings.py
        urls.py
        wsgi.py
        __init__.py

Folder my_url/ ở bên ngoài là một thư mục chứa toàn bộ project của chúng ta. Tên của nó không quan trọng, Django framework không quản lý cái tên này, bạn có thể đổi tên nó thành các tên khác nhau nếu muốn.

manage.py: Django's command-line utility for administrative tasks --> Nơi thực thi/truyền tải vào django-core các lệnh CLI từ django-admin. Nếu có thời gian, các bạn có thể tìm hiểu sâu hơn về các tác vụ mà django-core cung cấp thông qua manage.py từ link: django-admin and manage.py https://docs.djangoproject.com/en/3.1/ref/django-admin/

Thư mục my_url bên trong là thư mục chứa các module cần thiết để định nghĩa cho dự án của bạn.

my_url/__init__.py: Là file trống để quy định my_url là một package.

my_url/settings.py: Chứa các cài đặt/cấu hình của một dự án Django. Các bạn có thể tìm hiểu sâu hơn cách thức hoạt động của module settings.py tại link: https://docs.djangoproject.com/en/3.1/topics/settings/

my_url/urls.py: Nơi khai báo các Path-URL chính của dự án Django. Từ các path được khai báo trong file này, các URL sẽ được định nghĩa rõ ràng ở các file khác. Tham khảo thêm về urls tại: https://docs.djangoproject.com/en/3.1/topics/http/urls/

my_url/asgi.py: File cấu hình lưu trữ các thông tin dùng để thực hiện deploy lên webserver. Thông tin tham khảo: https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/

my_url/wsgi.py: File cấu hình lưu trữ các thông tin dùng để thực hiện deploy lên webserver. Thông tin tham khảo: https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/


Với khung thông tin hiện tại, chúng ta đã có thể thực hiện start website của mình lên để kiểm tra. Câu lệnh khởi động là: python manage.py runserver

(django3_venv)> python 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.
December 19, 2020 - 22:10:02
Django version 3.1.4, using settings 'my_url.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

Đến đây là chúng ta đã khởi tạo một website đang chạy trên localhost và cổng 8000.
Chúng ta sẽ thực hiện truy cập vào địa chỉ URL phía trên (http://127.0.0.1:8000) và xem kết quả hiện ra

Hướng dẫn url build python

Để thực hiện tắt ứng dụng, chúng ta thực hiện gõ CTRL - BREAK trên màn hình đen terminal.
Để ý thấy giá trị 8000 là giá trị mặc định của server port khi thực hiện khởi tạo webserver, giá trị này có thể thay đổi được bằng cách khi khởi động webserver, thêm giá trị port vào phía sau: python manage.py runserver 8080

(django3_venv) PS E:\code_learn\code\my_url> python manage.py runserver 8080
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.
December 19, 2020 - 22:20:51
Django version 3.1.4, using settings 'my_url.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK

Site của chúng ta sẽ khởi động và trỏ ra bên ngoài bằng port 8080.

4. Khởi tạo app.

Trong Django thì mỗi cụm chức năng sẽ được thiết kế như một python-package.
Ví dụ như website của chúng ta có một cụm chức năng là xử lý các url, như vậy chúng ta sẽ có một django-application là shortener_url.

Các tạo ra một django-app như sau:

python manage.py startapp shortener_url

Chúng ta thu được cấu trúc thư mục mới với thêm thư mục url_shortener:

my_url
│   db.sqlite3
│   manage.py
│
├───my_url
│   │   asgi.py
│   │   settings.py
│   │   urls.py
│   │   wsgi.py
│   │   __init__.py
│
└───url_shortener
    │   admin.py
    │   apps.py
    │   models.py
    │   tests.py
    │   views.py
    │   __init__.py
    │
    └───migrations
            __init__.py

Bên trong thư mục url_shortener, chúng ta có các file và dự kiến các chức năng của nó sẽ như sau:
admin.py: Chứa các thông tin liên quan đến việc triển khai module admin cho website.
apps.py: Nơi chứa các config của app.
models.py: Nơi chứa các khai báo đối tượng trong database của app
tests.py: Chứa các test case đùng để thực hiện unit-test.
views.py: Chứa các khung nhìn để thực hiện việc route và hiển thị dữ liệu về đúng hướng.

Chúng ta sẽ viết một view đơn giản để hiển thị ra câu chào mừng. Cách thực hiện sẽ như sau:
Bước 1: Mở url_shortener/views.py để tạo một function trả về câu chào mừng
Bước 2: Tạo file url_shortener/urls.py để định nghĩa path-url để trỏ đến view mới tạo.
Bước 3: Mở file my_url/urls.py để tạo định nghĩa url trỏ vào path-url đã định nghĩa tại url_shortener/urls.py.

Cụ thể các bước sẽ làm như sau:
Bước 1: Tạo views.
Mở file url_shortener/views.py, thêm đoạn code với nội dung như sau:

# url_shortener/views.py
from django.shortcuts import render
from django.http import HttpResponse


def index(request):
return HttpResponse("Xin chào, đây là hệ thống rút gọn link của công ty X. Tôi có thể giúp gì cho bạn?")

Đây là một view (khung nhìn) đơn giản của Django, muốn view có thể hiển thị được ra bên ngoài, chúng ta cần gán nó vào một URL. Việc gán này cần một config trong file urls.py. Để đơn giản, Django cho phép chúng ta tách riêng các URL với từng django-app, sau đó mới thực hiện map lại ở urls.py ở thư mục chính.

Bước 2: Tạo file url_shortener/urls.py
Sau khi tạo file, mở file và nhập vào nội dung như bên dưới

from django.urls import path
from . import views  # call to url_shortener/views.py

urlpatterns = [
    path('', views.index, name='index'),
]

Ở đây, ta thấy urlpattern trỏ vào views.index và có alias là 'index' (để dễ dành quản lý)

Bước 3: Mở file my_url/urls.py, thực hiện kết nối dữ liệu đã khai báo từ url_shortener/urls.py vào my_url/urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('url-shortener/', include('url_shortener.urls'))
]

Ở đây, chúng ta đã thêm vào function là include('url_shortener.urls'), function này cho phép thực hiện liên kết các url đến các file cấu hình url trong các django-app.

Thực hiện khởi chạy ứng dụng và truy nhập vào đường dẫn http://127.0.0.1:8000/url-shortener/, chúng ta sẽ thu được kết quả hiển thị ra màn hình:

Hướng dẫn url build python

5. Cài đặt database cho ứng dụng.

Mặc định thì Django sẽ cung cấp cho người dùng 1 database sử dụng sqlite3, đây là một dạng database file, với file dữ liệu được mặc định đặt tại thư mục gốc.
Chúng ta cũng có thể thay thế loại database hoặc kết nối vào database đã có bằng cách thay đổi các cấu hình tại file my_url/settings.py. Trong khuôn khổ bài viết này, tôi sẽ không hướng dẫn phần thay đổi này, hẹn các bạn vào các bài viết sau.

Để bắt đầu sử dụng database trong project của chúng ta, chúng ta sẽ thực hiện việc migrate dữ liệu các application mặc định vào database: python manage.py migrate

(django3_venv) > python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
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

Câu lệnh migrate sẽ thực hiện cài đặt các bảng dữ liệu cần thiết cho các module/app được đặt tại INSTALLED_APPS trong file my_url/settings.py.
Trong ví dụ của chúng ta, có các module/default-app sau:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Tương ứng với nó là các bảng dữ liệu sẽ được cài đặt vào database sau câu lệnh migrate:

Hướng dẫn url build python

6. Thiết kế models & thực hiện migrate dữ liệu.

Có nhiều phương án thiết kế cơ sở dữ liệu và gán nó vào source code như: code first, database first,...
Trong ví dụ này, chúng ta sẽ dùng code-first, nghĩa là chúng ta sẽ thiết kế các models trước sau đó thực hiện migrate để tạo bảng dữ liệu trong cơ sở dữ liệu. Mỗi model-class tương ứng với 1 bảng dữ liệu, mỗi property của model-class là một cột của bảng dữ liệu.

Phần models của Django được thiết kế theo DRY Principle (Don't repeat yourself - https://docs.djangoproject.com/en/3.1/misc/design-philosophies/#dry) nên source code của model-class sẽ đặt tập trung tại mỗi django-app nhưng cho phép truy cập từ các django-app khác nhau.

Mở file url_shortener/models.py, thực hiện định nghĩa một class như bên dưới

from django.db import models

class MyURL(models.Model):
    alias = models.CharField(max_length=200)
    url = models.CharField(max_length=5000)

Ở đây, chúng ta sẽ tiếp xúc với các từ khóa mới:
- django.db.models.Model: Được mô tả chi tiết tại https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model
- CharField: Một định dạng của class Field, các class đặc trưng cho datatype của trường dữ liệu được định nghĩa tại https://docs.djangoproject.com/en/3.1/ref/models/fields/

Để thực hiện activating các models mới được định nghĩa, chúng ta cần thực hiện khai báo ứng dụng vào đối tượng INSTALLED_APPS trong file my_url/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # New Local APP
    'url_shortener.apps.UrlShortenerConfig'
]

Thực hiện tạo file cho phép migration app mới cài đặt bằng câu lệnh: python manage.py makemigrations url_shortener

(django3_venv) > python manage.py makemigrations url_shortener
Migrations for 'url_shortener':
  url_shortener\migrations\0001_initial.py
    - Create model MyURL

Sau câu lệnh này, chúng ta thấy trong thư mục url_shortener\migrations xuất hiện một file có tên 0001_initial.py, có nội dung:

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='MyURL',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('alias', models.CharField(max_length=200)),
                ('url', models.CharField(max_length=5000)),
            ],
        ),
    ]

Đây chính là nội dung để chúng ta thực hiện migration vào database cho ứng dụng url_shortener. Cách thực hiện là dùng câu lệnh: python manage.py sqlmigrate url_shortener 0001

(django3_venv) > python manage.py sqlmigrate url_shortener 0001
BEGIN;
--
-- Create model MyURL
--
CREATE TABLE "url_shortener_myurl" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "alias" varchar(200) NOT NULL, "url" varchar(5000) NOT NULL);
COMMIT;

Câu lệnh trên sẽ nạp dữ liệu bảng trên vào cache của django-admin, để thực sự có bảng dữ liệu, chúng ta cần thực hiện migrate dữ liệu một lần nữa.

(django3_venv) > python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, url_shortener
Running migrations:
  Applying url_shortener.0001_initial... OK

Mở database db.sqlite3, chúng ta sẽ thấy có thêm một bảng dữ liệu có tên url_shortener_myurl.

7. Django-admin

Đây là một trong số những tính năng làm nên thương hiệu "rapidly-application" của Django. Chỉ cần có models, có bảng dữ liệu là có thể xây dựng xong giao diện admin gồm các chức năng CRUD đơn giản.
Để bắt đầu, thực hiện gõ dòng sau vào command-line:

python manage.py createsuperuser

Sau đó, thực hiện nhập thông tin cơ bản như username, email, password. Đây là thông tin superuser nên cần phải ... tự nhớ.

(django_venv)>python manage.py createsuperuser
Username (leave blank to use 'quangvinh2986'): admin
Email address: [email protected]
Password:
Password (again):
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

Đến đây, khi thực hiện start ứng dụng, thực hiện truy nhập vào trang web http://127.0.0.1:8000/admin/, chúng ta sẽ được yêu cầu thực hiện đăng nhập. Lúc này, sẽ thực hiện đăng nhập bằng tài khoản superuser đã tạo phía trên.
Sau khi đăng nhập thành công, website sẽ thực hiện hiển thị ra trang quản lý "Site administration". Tại thời điểm này, tại Site administration chỉ chứa thông tin quản trị về Group & User. Để thực hiện đưa phần admin (CRUD) của Shorten_URL vào, cần thực hiện khai báo vào file shortener_url/admin.py

from django.contrib import admin
from .models import MyURL

admin.site.register(MyURL)

Thực hiện restart lại ứng dụng hoặc refresh lại admin site (trường hợp đặt DEBUG=True)

Hướng dẫn url build python

Nhấn vào "My url", chuyển sang trang quản lý dữ liệu của app.

Hướng dẫn url build python

Từ đây, chúng ta có thể thực hiện việc Thêm/sửa/xóa các bản ghi.
Sau khi thêm một số bản ghi vào, chúng ta sẽ có danh sách các bản ghi được hiển thị:

Hướng dẫn url build python

Nhấn vào một link chi tiết, chúng ta thu được:

Hướng dẫn url build python

8. Hiển thị danh sách dữ liệu dưới góc nhìn của một normal user

Giả sử chúng ta sẽ thực hiện liệt kê tất cả các dữ liệu alias/url đang có trong database ra một danh sách. Sau đó user có thể lựa chọn mở thử link theo alias xem có thực hiện redirect sang đúng link ở url hay không.
Để bắt đầu làm, chúng ta sẽ mở file url_shortener/views.py, bổ sung thêm đoạn code thực hiện import model MyURL

from .models import MyURL

Thực hiện thêm function dưới đây để trả về danh sách các url và alias tương ứng.

from .models import MyURL


def list_url(request):
    my_urls = MyURL.objects.all()
    template = '/url-shortener/{alias} --> {url}
' value = "" for my_url in my_urls: value += template.format(alias=my_url.alias, url=my_url.url) return HttpResponse(value)

Trong đó câu lệnh `urls = MyURL.objects ` có nghĩa là lấy tất cả bản ghi của bảng MyURL
Sau đó mở file url_shortener/urls.py, thực hiện thêm url cho trang hiển thị danh sách.

urlpatterns = [
    path('', views.index, name='index'),
    path('list', views.list_url, name='list')
]

Thực hiện khởi tạo server và truy cập vào link: http://127.0.0.1:8000/url-shortener/list, chúng ta sẽ thu được kết quả:

Hướng dẫn url build python

9. Xử lý khi người dùng mở một link có chứa alias.

Từ danh sách hiển thị phía trên, nếu người dùng nhấn vào 1 link bất kỳ ví dụ: http://127.0.0.1:8000/url-shortener/detail/profile/, nhiệm vụ của chúng ta là phải viết code để thực hiện lấy ra giá trị là link kết nối: https://codelearn.io/sharing/how-to-profiling-python-application

Mở file url_shortener/views.py, bổ sung thêm đoạn code thực hiện lấy ra dữ liệu từng bản ghi theo alias

from django.shortcuts import redirect

def detail(request, alias):
    try:
        my_url = MyURL.objects.get(alias=alias)
    except MyURL.DoesNotExist:
        raise Http404("alias does not exist")
    return redirect(my_url.url)

Mở url_shortener/urls.py để bổ sung thêm routing: path('detail/', views.detail, name='detail')

Đến đây ta quay lại trang list lúc nãy và thực hiện ấn vào các link shorten đã có sẵn, kết quả sẽ dẫn chúng ta đến trạng url gốc.

Hướng dẫn url build python

Kết.

Trên đây là một ví dụ nhỏ về việc tạo nhanh một ứng dụng web với python-django. Dự kiến tôi sẽ viết thành 1 series bài viết liên quan đến Django, các phần sau của bài viết này sẽ có trong những tuần tiếp theo. Cảm ơn các bạn đã đọc bài viết của tôi.

Link tham khảo: https://docs.djangoproject.com/en/3.1/intro/tutorial01/
Source code tham khảo: https://github.com/quangvinh2986/django-url-shortener