Hoang Tran

Hoang Tran

1656861060

Bắt Đầu Với Chế Độ Xem Không Đồng Bộ Của Django

Viết mã không đồng bộ cung cấp cho bạn khả năng tăng tốc ứng dụng của mình mà không tốn nhiều công sức. Các phiên bản Django> = 3.1 hỗ trợ chế độ xem không đồng bộ, phần mềm trung gian và các thử nghiệm. Nếu bạn chưa thử nghiệm với chế độ xem không đồng bộ, bây giờ là thời điểm tuyệt vời để bạn có được chúng.

Hướng dẫn này xem xét cách bắt đầu với các chế độ xem không đồng bộ của Django.

Nếu bạn quan tâm đến việc tìm hiểu thêm về sức mạnh đằng sau mã không đồng bộ cùng với sự khác biệt giữa các luồng, đa xử lý và không đồng bộ trong Python, hãy xem bài viết Tăng tốc Python với Concurrency, Parallelism và asyncio của tôi .

Mục tiêu

Đến cuối hướng dẫn này, bạn sẽ có thể:

  1. Viết chế độ xem không đồng bộ trong Django
  2. Thực hiện một yêu cầu HTTP không chặn trong chế độ xem Django
  3. Đơn giản hóa các tác vụ nền cơ bản với chế độ xem không đồng bộ của Django
  4. Sử dụng sync_to_asyncđể thực hiện cuộc gọi đồng bộ bên trong chế độ xem không đồng bộ
  5. Giải thích khi nào bạn nên và không nên sử dụng chế độ xem không đồng bộ

Bạn cũng có thể trả lời các câu hỏi sau:

  1. Điều gì sẽ xảy ra nếu bạn thực hiện cuộc gọi đồng bộ bên trong chế độ xem không đồng bộ?
  2. Điều gì sẽ xảy ra nếu bạn thực hiện một cuộc gọi đồng bộ và không đồng bộ bên trong một chế độ xem không đồng bộ?
  3. Cần tây có còn cần thiết với các chế độ xem không đồng bộ của Django không?

Điều kiện tiên quyết

Miễn là bạn đã quen thuộc với chính Django, việc thêm chức năng không đồng bộ vào các chế độ xem không dựa trên lớp là cực kỳ đơn giản.

Sự phụ thuộc

  1. Python> = 3,10
  2. Django> = 4.0
  3. Uvicorn
  4. HTTPX

ASGI là gì?

ASGI là viết tắt của Asynchronous Server Gateway Interface. Đó là phiên bản tiếp theo không đồng bộ, hiện đại đối với WSGI , cung cấp một tiêu chuẩn để tạo các ứng dụng web dựa trên Python không đồng bộ.

Một điều đáng nói khác là ASGI tương thích ngược với WSGI, đây là lý do tốt để chuyển từ máy chủ WSGI như Gunicorn hoặc uWSGI sang máy chủ ASGI như Uvicorn hoặc Daphne ngay cả khi bạn chưa sẵn sàng chuyển sang viết ứng dụng không đồng bộ .

Tạo ứng dụng

Tạo một thư mục dự án mới cùng với một dự án Django mới:

$ mkdir django-async-views && cd django-async-views
$ python3.10 -m venv env
$ source env/bin/activate

(env)$ pip install django
(env)$ django-admin startproject hello_async .

Hãy trao đổi virtualenv và Pip cho thơ hoặc Pipenv . Để biết thêm, hãy xem lại Môi trường Python hiện đại .

Django sẽ chạy các chế độ xem không đồng bộ của bạn nếu bạn đang sử dụng máy chủ phát triển tích hợp sẵn, nhưng nó sẽ không thực sự chạy chúng một cách không đồng bộ, vì vậy chúng tôi sẽ chạy Django với Uvicorn.

Cài đặt nó:

(env)$ pip install uvicorn

Để chạy dự án của bạn với Uvicorn, bạn sử dụng lệnh sau từ thư mục gốc của dự án:

uvicorn {name of your project}.asgi:application

Trong trường hợp của chúng tôi, đây sẽ là:

(env)$ uvicorn hello_async.asgi:application

Tiếp theo, hãy tạo chế độ xem không đồng bộ đầu tiên của chúng ta. Thêm tệp mới để giữ các dạng xem của bạn trong thư mục "hello_async", rồi thêm dạng xem sau:

# hello_async/views.py

from django.http import HttpResponse


async def index(request):
    return HttpResponse("Hello, async Django!")

Tạo chế độ xem không đồng bộ trong Django cũng đơn giản như tạo chế độ xem đồng bộ - tất cả những gì bạn cần làm là thêm asynctừ khóa.

Cập nhật các URL:

# hello_async/urls.py

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

from hello_async.views import index


urlpatterns = [
    path("admin/", admin.site.urls),
    path("", index),
]

Bây giờ, trong một thiết bị đầu cuối, trong thư mục gốc của bạn, hãy chạy:

(env)$ uvicorn hello_async.asgi:application --reload

Cờ --reloadyêu cầu Uvicorn xem các tệp của bạn để biết các thay đổi và tải lại nếu tìm thấy bất kỳ thay đổi nào. Điều đó có lẽ đã tự giải thích.

Mở http: // localhost: 8000 / trong trình duyệt web yêu thích của bạn:

Hello, async Django!

Không phải là điều thú vị nhất trên thế giới, nhưng, đây là một sự khởi đầu. Cần lưu ý rằng việc chạy chế độ xem này với máy chủ phát triển tích hợp sẵn của Django sẽ dẫn đến chức năng và đầu ra giống hệt nhau. Điều này là do chúng tôi không thực sự làm bất kỳ điều gì không đồng bộ trong trình xử lý.

HTTPX

Cần lưu ý rằng hỗ trợ không đồng bộ hoàn toàn tương thích ngược, vì vậy bạn có thể kết hợp chế độ xem không đồng bộ và đồng bộ hóa, phần mềm trung gian và thử nghiệm. Django sẽ thực thi từng thứ trong ngữ cảnh thực thi thích hợp.

Để chứng minh điều này, hãy thêm một vài chế độ xem mới:

# hello_async/views.py

import asyncio
from time import sleep

import httpx
from django.http import HttpResponse


# helpers

async def http_call_async():
    for num in range(1, 6):
        await asyncio.sleep(1)
        print(num)
    async with httpx.AsyncClient() as client:
        r = await client.get("https://httpbin.org/")
        print(r)


def http_call_sync():
    for num in range(1, 6):
        sleep(1)
        print(num)
    r = httpx.get("https://httpbin.org/")
    print(r)


# views

async def index(request):
    return HttpResponse("Hello, async Django!")


async def async_view(request):
    loop = asyncio.get_event_loop()
    loop.create_task(http_call_async())
    return HttpResponse("Non-blocking HTTP request")


def sync_view(request):
    http_call_sync()
    return HttpResponse("Blocking HTTP request")

Cập nhật các URL:

# hello_async/urls.py

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

from hello_async.views import index, async_view, sync_view


urlpatterns = [
    path("admin/", admin.site.urls),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Cài đặt HTTPX :

(env)$ pip install httpx

Khi máy chủ đang chạy, điều hướng đến http: // localhost: 8000 / async / . Bạn sẽ thấy ngay phản hồi:

Non-blocking HTTP request

Trong thiết bị đầu cuối của bạn, bạn sẽ thấy:

INFO:     127.0.0.1:60374 - "GET /async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Tại đây, phản hồi HTTP được gửi lại trước lệnh gọi ngủ đầu tiên.

Tiếp theo, điều hướng đến http: // localhost: 8000 / sync / . Sẽ mất khoảng năm giây để nhận được phản hồi:

Blocking HTTP request

Chuyển sang thiết bị đầu cuối:

1
2
3
4
5
<Response [200 OK]>
INFO:     127.0.0.1:60375 - "GET /sync/ HTTP/1.1" 200 OK

Tại đây, phản hồi HTTP được gửi sau vòng lặp và yêu cầu https://httpbin.org/hoàn tất.

Hút một số loại thịt

Để mô phỏng thêm một kịch bản trong thế giới thực về cách bạn tận dụng tính năng không đồng bộ, hãy xem cách chạy nhiều hoạt động không đồng bộ, tổng hợp kết quả và trả lại chúng cho người gọi.

Quay lại URLconf của dự án của bạn, tạo một đường dẫn mới tại smoke_some_meats:

# hello_async/urls.py

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

from hello_async.views import index, async_view, sync_view, smoke_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Quay lại dạng xem của bạn, tạo một hàm trợ giúp không đồng bộ mới được gọi là smoke. Hàm này nhận hai tham số: danh sách các chuỗi được gọi smokablesvà một chuỗi được gọi flavor. Những thứ này được mặc định là danh sách các loại thịt hun khói và "Sweet Baby Ray's", tương ứng.

# hello_async/views.py

async def smoke(smokables: List[str] = None, flavor: str = "Sweet Baby Ray's") -> List[str]:
    """ Smokes some meats and applies the Sweet Baby Ray's """

    for smokable in smokables:
        print(f"Smoking some {smokable}...")
        print(f"Applying the {flavor}...")
        print(f"{smokable.capitalize()} smoked.")

    return len(smokables)

Vòng lặp for áp dụng một cách không đồng bộ hương vị (đọc là: Sweet Baby Ray's) cho các loại thịt hun khói (đọc là: thịt hun khói).

Đừng quên nhập:

from typing import List

Listđược sử dụng cho khả năng đánh máy bổ sung. Điều này là không bắt buộc và có thể dễ dàng bị bỏ qua (chỉ cần bỏ qua phần : List[str]khai báo tham số "smokingables" sau đây).

Tiếp theo, thêm hai trình trợ giúp không đồng bộ khác:

async def get_smokables():
    print("Getting smokeables...")

    await asyncio.sleep(2)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning smokeable")
        return [
            "ribs",
            "brisket",
            "lemon chicken",
            "salmon",
            "bison sirloin",
            "sausage",
        ]


async def get_flavor():
    print("Getting flavor...")

    await asyncio.sleep(1)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning flavor")
        return random.choice(
            [
                "Sweet Baby Ray's",
                "Stubb's Original",
                "Famous Dave's",
            ]
        )

Đảm bảo thêm nhập:

import random

Tạo dạng xem không đồng bộ sử dụng các chức năng không đồng bộ:

# hello_async/views.py

async def smoke_some_meats(request):
    results = await asyncio.gather(*[get_smokables(), get_flavor()])
    total = await asyncio.gather(*[smoke(results[0], results[1])])
    return HttpResponse(f"Smoked {total[0]} meats with {results[1]}!")

Dạng xem này gọi hàm get_smokablesget_flavorđồng thời. Vì smokephụ thuộc vào kết quả từ cả hai get_smokablesget_flavor, chúng tôi đã từng gatherđợi mỗi tác vụ không đồng bộ hoàn thành.

Hãy nhớ rằng điều đó trong chế độ xem đồng bộ hóa thông thường get_smokablesget_flavorsẽ được xử lý từng cái một. Ngoài ra, chế độ xem không đồng bộ sẽ mang lại hiệu quả thực thi và cho phép các yêu cầu khác được xử lý trong khi các tác vụ không đồng bộ được xử lý, cho phép nhiều yêu cầu hơn được xử lý bởi cùng một quy trình trong một khoảng thời gian cụ thể.

Cuối cùng, một phản hồi được trả lại để cho người dùng biết rằng bữa ăn BBQ ngon của họ đã sẵn sàng.

Tuyệt quá. Lưu tệp, sau đó quay lại trình duyệt của bạn và điều hướng đến http: // localhost: 8000 / khói_some_meats / . Sẽ mất vài giây để nhận được phản hồi:

Smoked 6 meats with Sweet Baby Ray's!

Trong bảng điều khiển của mình, bạn sẽ thấy:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Smoking some ribs...
Applying the Stubb's Original...
Ribs smoked.
Smoking some brisket...
Applying the Stubb's Original...
Brisket smoked.
Smoking some lemon chicken...
Applying the Stubb's Original...
Lemon chicken smoked.
Smoking some salmon...
Applying the Stubb's Original...
Salmon smoked.
Smoking some bison sirloin...
Applying the Stubb's Original...
Bison sirloin smoked.
Smoking some sausage...
Applying the Stubb's Original...
Sausage smoked.
INFO:     127.0.0.1:57501 - "GET /smoke_some_meats/ HTTP/1.1" 200 OK

Hãy lưu ý thứ tự của các câu lệnh in sau:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Đây là sự không đồng bộ khi làm việc: Khi get_smokableshàm ở chế độ ngủ, get_flavorhàm sẽ kết thúc quá trình xử lý.

Thịt cháy

Đồng bộ hóa cuộc gọi

Hỏi: Điều gì sẽ xảy ra nếu bạn thực hiện cuộc gọi đồng bộ bên trong chế độ xem không đồng bộ?

Điều tương tự sẽ xảy ra nếu bạn gọi một hàm không đồng bộ từ một chế độ xem không đồng bộ.

--

Để minh họa điều này, hãy tạo một hàm trợ giúp mới trong views.py của bạn được gọi là oversmoke:

# hello_async/views.py

def oversmoke() -> None:
    """ If it's not dry, it must be uncooked """
    sleep(5)
    print("Who doesn't love burnt meats?")

Rất đơn giản: Chúng tôi chỉ đợi đồng bộ trong năm giây.

Tạo dạng xem gọi hàm này:

# hello_async/views.py

async def burn_some_meats(request):
    oversmoke()
    return HttpResponse(f"Burned some meats.")

Cuối cùng, sắp xếp lộ trình trong URLconf của dự án của bạn:

# hello_async/urls.py

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

from hello_async.views import index, async_view, sync_view, smoke_some_meats, burn_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Truy cập tuyến đường trong trình duyệt tại http: // localhost: 8000 / burn_some_meats :

Burned some meats.

Lưu ý rằng phải mất năm giây để cuối cùng nhận được phản hồi từ trình duyệt. Bạn cũng nên nhận được đầu ra bảng điều khiển cùng một lúc:

Who doesn't love burnt meats?
INFO:     127.0.0.1:40682 - "GET /burn_some_meats HTTP/1.1" 200 OK

Có thể đáng lưu ý rằng điều tương tự sẽ xảy ra bất kể máy chủ bạn đang sử dụng, có thể là WSGI hoặc dựa trên ASGI.

Đồng bộ hóa và không đồng bộ hóa cuộc gọi

Hỏi: Điều gì sẽ xảy ra nếu bạn thực hiện một cuộc gọi đồng bộ và không đồng bộ bên trong một chế độ xem không đồng bộ?

Đừng làm điều này.

Chế độ xem đồng bộ và không đồng bộ có xu hướng hoạt động tốt nhất cho các mục đích khác nhau. Nếu bạn có chức năng chặn trong chế độ xem không đồng bộ, thì tốt nhất nó sẽ không tốt hơn là chỉ sử dụng chế độ xem đồng bộ.

Đồng bộ với không đồng bộ

Nếu bạn cần thực hiện cuộc gọi đồng bộ bên trong dạng xem không đồng bộ (ví dụ như tương tác với cơ sở dữ liệu thông qua Django ORM), hãy sử dụng sync_to_async làm trình bao bọc hoặc trình trang trí.

Thí dụ:

# hello_async/views.py

async def async_with_sync_view(request):
    loop = asyncio.get_event_loop()
    async_function = sync_to_async(http_call_sync, thread_sensitive=False)
    loop.create_task(async_function())
    return HttpResponse("Non-blocking HTTP request (via sync_to_async)")

Bạn có nhận thấy rằng chúng tôi đã đặt thread_sensitivethông số thành Falsekhông? Điều này có nghĩa là hàm đồng bộ http_call_sync, sẽ được chạy trong một luồng mới. Xem lại các tài liệu để biết thêm thông tin.

Thêm nhập vào đầu:

from asgiref.sync import sync_to_async

Thêm URL:

# hello_async/urls.py

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

from hello_async.views import (
    index,
    async_view,
    sync_view,
    smoke_some_meats,
    burn_some_meats,
    async_with_sync_view
)


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("sync_to_async/", async_with_sync_view),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Kiểm tra nó trong trình duyệt của bạn tại http: // localhost: 8000 / sync_to_async / .

Trong thiết bị đầu cuối của bạn, bạn sẽ thấy:

INFO:     127.0.0.1:61365 - "GET /sync_to_async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Bằng cách sử dụng sync_to_async, cuộc gọi đồng bộ chặn đã được xử lý trong một chuỗi nền, cho phép phản hồi HTTP được gửi lại trước cuộc gọi ngủ đầu tiên.

Chế độ xem cần tây và không đồng bộ

Q: Celery có còn cần thiết với các chế độ xem không đồng bộ của Django không?

Nó phụ thuộc.

Các chế độ xem không đồng bộ của Django cung cấp chức năng tương tự như một tác vụ hoặc hàng đợi tin nhắn mà không phức tạp. Nếu bạn đang sử dụng (hoặc đang cân nhắc) Django và muốn làm điều gì đó đơn giản (và không quan tâm đến độ tin cậy), chế độ xem không đồng bộ là một cách tuyệt vời để thực hiện điều này một cách nhanh chóng và dễ dàng. Nếu bạn cần thực hiện các quy trình nền chạy lâu và nặng hơn nhiều, bạn sẽ vẫn muốn sử dụng Celery hoặc RQ.

Cần lưu ý rằng để sử dụng các chế độ xem không đồng bộ một cách hiệu quả, bạn chỉ nên có các lệnh gọi không đồng bộ trong chế độ xem. Mặt khác, hàng đợi tác vụ sử dụng công nhân trên các quy trình riêng biệt và do đó có khả năng chạy các lệnh gọi đồng bộ trong nền, trên nhiều máy chủ.

Nhân tiện, bạn không phải chọn giữa chế độ xem không đồng bộ và hàng đợi tin nhắn - bạn có thể dễ dàng sử dụng chúng song song. Ví dụ: Bạn có thể sử dụng chế độ xem không đồng bộ để gửi email hoặc thực hiện sửa đổi cơ sở dữ liệu một lần, nhưng hãy yêu cầu Celery dọn dẹp cơ sở dữ liệu của bạn vào thời gian đã định mỗi đêm hoặc tạo và gửi báo cáo khách hàng.

Khi nào sử dụng

Đối với các dự án greenfield, nếu không đồng bộ là sở thích của bạn, hãy tận dụng các chế độ xem không đồng bộ và viết các quy trình I / O của bạn theo cách không đồng bộ càng nhiều càng tốt. Điều đó nói rằng, nếu hầu hết các chế độ xem của bạn chỉ cần thực hiện lệnh gọi đến cơ sở dữ liệu và thực hiện một số xử lý cơ bản trước khi trả lại dữ liệu, bạn sẽ không thấy sự gia tăng nhiều (nếu có) so với việc chỉ gắn bó với các chế độ xem đồng bộ.

Đối với các dự án brownfield, nếu bạn có ít hoặc không có quá trình I / O thì hãy gắn với chế độ xem đồng bộ. Nếu bạn có một số quy trình I / O, hãy kiểm tra xem bạn sẽ dễ dàng viết lại chúng theo cách không đồng bộ như thế nào. Viết lại I / O đồng bộ hóa thành không đồng bộ không dễ dàng, vì vậy có thể bạn sẽ muốn tối ưu hóa I / O đồng bộ hóa và chế độ xem của mình trước khi cố gắng viết lại thành không đồng bộ. Ngoài ra, không bao giờ là một ý tưởng hay khi kết hợp các quy trình đồng bộ hóa với các chế độ xem không đồng bộ của bạn.

Trong quá trình sản xuất, hãy đảm bảo sử dụng Gunicorn để quản lý Uvicorn nhằm tận dụng lợi thế của cả đồng thời (thông qua Uvicorn) và song song (thông qua Gunicorn worker):

gunicorn -w 3 -k uvicorn.workers.UvicornWorker hello_async.asgi:application

Sự kết luận

Tóm lại, mặc dù đây là một trường hợp sử dụng đơn giản, nhưng nó sẽ cung cấp cho bạn một ý tưởng sơ bộ về các khả năng mà các khung nhìn không đồng bộ của Django mở ra. Một số điều khác cần thử trong chế độ xem không đồng bộ của bạn là gửi email, gọi API của bên thứ ba và đọc / ghi vào tệp.

Nguồn:  https://testdriven.io

#django #async 

What is GEEK

Buddha Community

Bắt Đầu Với Chế Độ Xem Không Đồng Bộ Của Django
Ahebwe  Oscar

Ahebwe Oscar

1620177818

Django admin full Customization step by step

Welcome to my blog , hey everyone in this article you learn how to customize the Django app and view in the article you will know how to register  and unregister  models from the admin view how to add filtering how to add a custom input field, and a button that triggers an action on all objects and even how to change the look of your app and page using the Django suit package let’s get started.

Database

Custom Titles of Django Admin

Exclude in Django Admin

Fields in Django Admin

#django #create super user django #customize django admin dashboard #django admin #django admin custom field display #django admin customization #django admin full customization #django admin interface #django admin register all models #django customization

Hoang Tran

Hoang Tran

1656861060

Bắt Đầu Với Chế Độ Xem Không Đồng Bộ Của Django

Viết mã không đồng bộ cung cấp cho bạn khả năng tăng tốc ứng dụng của mình mà không tốn nhiều công sức. Các phiên bản Django> = 3.1 hỗ trợ chế độ xem không đồng bộ, phần mềm trung gian và các thử nghiệm. Nếu bạn chưa thử nghiệm với chế độ xem không đồng bộ, bây giờ là thời điểm tuyệt vời để bạn có được chúng.

Hướng dẫn này xem xét cách bắt đầu với các chế độ xem không đồng bộ của Django.

Nếu bạn quan tâm đến việc tìm hiểu thêm về sức mạnh đằng sau mã không đồng bộ cùng với sự khác biệt giữa các luồng, đa xử lý và không đồng bộ trong Python, hãy xem bài viết Tăng tốc Python với Concurrency, Parallelism và asyncio của tôi .

Mục tiêu

Đến cuối hướng dẫn này, bạn sẽ có thể:

  1. Viết chế độ xem không đồng bộ trong Django
  2. Thực hiện một yêu cầu HTTP không chặn trong chế độ xem Django
  3. Đơn giản hóa các tác vụ nền cơ bản với chế độ xem không đồng bộ của Django
  4. Sử dụng sync_to_asyncđể thực hiện cuộc gọi đồng bộ bên trong chế độ xem không đồng bộ
  5. Giải thích khi nào bạn nên và không nên sử dụng chế độ xem không đồng bộ

Bạn cũng có thể trả lời các câu hỏi sau:

  1. Điều gì sẽ xảy ra nếu bạn thực hiện cuộc gọi đồng bộ bên trong chế độ xem không đồng bộ?
  2. Điều gì sẽ xảy ra nếu bạn thực hiện một cuộc gọi đồng bộ và không đồng bộ bên trong một chế độ xem không đồng bộ?
  3. Cần tây có còn cần thiết với các chế độ xem không đồng bộ của Django không?

Điều kiện tiên quyết

Miễn là bạn đã quen thuộc với chính Django, việc thêm chức năng không đồng bộ vào các chế độ xem không dựa trên lớp là cực kỳ đơn giản.

Sự phụ thuộc

  1. Python> = 3,10
  2. Django> = 4.0
  3. Uvicorn
  4. HTTPX

ASGI là gì?

ASGI là viết tắt của Asynchronous Server Gateway Interface. Đó là phiên bản tiếp theo không đồng bộ, hiện đại đối với WSGI , cung cấp một tiêu chuẩn để tạo các ứng dụng web dựa trên Python không đồng bộ.

Một điều đáng nói khác là ASGI tương thích ngược với WSGI, đây là lý do tốt để chuyển từ máy chủ WSGI như Gunicorn hoặc uWSGI sang máy chủ ASGI như Uvicorn hoặc Daphne ngay cả khi bạn chưa sẵn sàng chuyển sang viết ứng dụng không đồng bộ .

Tạo ứng dụng

Tạo một thư mục dự án mới cùng với một dự án Django mới:

$ mkdir django-async-views && cd django-async-views
$ python3.10 -m venv env
$ source env/bin/activate

(env)$ pip install django
(env)$ django-admin startproject hello_async .

Hãy trao đổi virtualenv và Pip cho thơ hoặc Pipenv . Để biết thêm, hãy xem lại Môi trường Python hiện đại .

Django sẽ chạy các chế độ xem không đồng bộ của bạn nếu bạn đang sử dụng máy chủ phát triển tích hợp sẵn, nhưng nó sẽ không thực sự chạy chúng một cách không đồng bộ, vì vậy chúng tôi sẽ chạy Django với Uvicorn.

Cài đặt nó:

(env)$ pip install uvicorn

Để chạy dự án của bạn với Uvicorn, bạn sử dụng lệnh sau từ thư mục gốc của dự án:

uvicorn {name of your project}.asgi:application

Trong trường hợp của chúng tôi, đây sẽ là:

(env)$ uvicorn hello_async.asgi:application

Tiếp theo, hãy tạo chế độ xem không đồng bộ đầu tiên của chúng ta. Thêm tệp mới để giữ các dạng xem của bạn trong thư mục "hello_async", rồi thêm dạng xem sau:

# hello_async/views.py

from django.http import HttpResponse


async def index(request):
    return HttpResponse("Hello, async Django!")

Tạo chế độ xem không đồng bộ trong Django cũng đơn giản như tạo chế độ xem đồng bộ - tất cả những gì bạn cần làm là thêm asynctừ khóa.

Cập nhật các URL:

# hello_async/urls.py

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

from hello_async.views import index


urlpatterns = [
    path("admin/", admin.site.urls),
    path("", index),
]

Bây giờ, trong một thiết bị đầu cuối, trong thư mục gốc của bạn, hãy chạy:

(env)$ uvicorn hello_async.asgi:application --reload

Cờ --reloadyêu cầu Uvicorn xem các tệp của bạn để biết các thay đổi và tải lại nếu tìm thấy bất kỳ thay đổi nào. Điều đó có lẽ đã tự giải thích.

Mở http: // localhost: 8000 / trong trình duyệt web yêu thích của bạn:

Hello, async Django!

Không phải là điều thú vị nhất trên thế giới, nhưng, đây là một sự khởi đầu. Cần lưu ý rằng việc chạy chế độ xem này với máy chủ phát triển tích hợp sẵn của Django sẽ dẫn đến chức năng và đầu ra giống hệt nhau. Điều này là do chúng tôi không thực sự làm bất kỳ điều gì không đồng bộ trong trình xử lý.

HTTPX

Cần lưu ý rằng hỗ trợ không đồng bộ hoàn toàn tương thích ngược, vì vậy bạn có thể kết hợp chế độ xem không đồng bộ và đồng bộ hóa, phần mềm trung gian và thử nghiệm. Django sẽ thực thi từng thứ trong ngữ cảnh thực thi thích hợp.

Để chứng minh điều này, hãy thêm một vài chế độ xem mới:

# hello_async/views.py

import asyncio
from time import sleep

import httpx
from django.http import HttpResponse


# helpers

async def http_call_async():
    for num in range(1, 6):
        await asyncio.sleep(1)
        print(num)
    async with httpx.AsyncClient() as client:
        r = await client.get("https://httpbin.org/")
        print(r)


def http_call_sync():
    for num in range(1, 6):
        sleep(1)
        print(num)
    r = httpx.get("https://httpbin.org/")
    print(r)


# views

async def index(request):
    return HttpResponse("Hello, async Django!")


async def async_view(request):
    loop = asyncio.get_event_loop()
    loop.create_task(http_call_async())
    return HttpResponse("Non-blocking HTTP request")


def sync_view(request):
    http_call_sync()
    return HttpResponse("Blocking HTTP request")

Cập nhật các URL:

# hello_async/urls.py

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

from hello_async.views import index, async_view, sync_view


urlpatterns = [
    path("admin/", admin.site.urls),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Cài đặt HTTPX :

(env)$ pip install httpx

Khi máy chủ đang chạy, điều hướng đến http: // localhost: 8000 / async / . Bạn sẽ thấy ngay phản hồi:

Non-blocking HTTP request

Trong thiết bị đầu cuối của bạn, bạn sẽ thấy:

INFO:     127.0.0.1:60374 - "GET /async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Tại đây, phản hồi HTTP được gửi lại trước lệnh gọi ngủ đầu tiên.

Tiếp theo, điều hướng đến http: // localhost: 8000 / sync / . Sẽ mất khoảng năm giây để nhận được phản hồi:

Blocking HTTP request

Chuyển sang thiết bị đầu cuối:

1
2
3
4
5
<Response [200 OK]>
INFO:     127.0.0.1:60375 - "GET /sync/ HTTP/1.1" 200 OK

Tại đây, phản hồi HTTP được gửi sau vòng lặp và yêu cầu https://httpbin.org/hoàn tất.

Hút một số loại thịt

Để mô phỏng thêm một kịch bản trong thế giới thực về cách bạn tận dụng tính năng không đồng bộ, hãy xem cách chạy nhiều hoạt động không đồng bộ, tổng hợp kết quả và trả lại chúng cho người gọi.

Quay lại URLconf của dự án của bạn, tạo một đường dẫn mới tại smoke_some_meats:

# hello_async/urls.py

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

from hello_async.views import index, async_view, sync_view, smoke_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Quay lại dạng xem của bạn, tạo một hàm trợ giúp không đồng bộ mới được gọi là smoke. Hàm này nhận hai tham số: danh sách các chuỗi được gọi smokablesvà một chuỗi được gọi flavor. Những thứ này được mặc định là danh sách các loại thịt hun khói và "Sweet Baby Ray's", tương ứng.

# hello_async/views.py

async def smoke(smokables: List[str] = None, flavor: str = "Sweet Baby Ray's") -> List[str]:
    """ Smokes some meats and applies the Sweet Baby Ray's """

    for smokable in smokables:
        print(f"Smoking some {smokable}...")
        print(f"Applying the {flavor}...")
        print(f"{smokable.capitalize()} smoked.")

    return len(smokables)

Vòng lặp for áp dụng một cách không đồng bộ hương vị (đọc là: Sweet Baby Ray's) cho các loại thịt hun khói (đọc là: thịt hun khói).

Đừng quên nhập:

from typing import List

Listđược sử dụng cho khả năng đánh máy bổ sung. Điều này là không bắt buộc và có thể dễ dàng bị bỏ qua (chỉ cần bỏ qua phần : List[str]khai báo tham số "smokingables" sau đây).

Tiếp theo, thêm hai trình trợ giúp không đồng bộ khác:

async def get_smokables():
    print("Getting smokeables...")

    await asyncio.sleep(2)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning smokeable")
        return [
            "ribs",
            "brisket",
            "lemon chicken",
            "salmon",
            "bison sirloin",
            "sausage",
        ]


async def get_flavor():
    print("Getting flavor...")

    await asyncio.sleep(1)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning flavor")
        return random.choice(
            [
                "Sweet Baby Ray's",
                "Stubb's Original",
                "Famous Dave's",
            ]
        )

Đảm bảo thêm nhập:

import random

Tạo dạng xem không đồng bộ sử dụng các chức năng không đồng bộ:

# hello_async/views.py

async def smoke_some_meats(request):
    results = await asyncio.gather(*[get_smokables(), get_flavor()])
    total = await asyncio.gather(*[smoke(results[0], results[1])])
    return HttpResponse(f"Smoked {total[0]} meats with {results[1]}!")

Dạng xem này gọi hàm get_smokablesget_flavorđồng thời. Vì smokephụ thuộc vào kết quả từ cả hai get_smokablesget_flavor, chúng tôi đã từng gatherđợi mỗi tác vụ không đồng bộ hoàn thành.

Hãy nhớ rằng điều đó trong chế độ xem đồng bộ hóa thông thường get_smokablesget_flavorsẽ được xử lý từng cái một. Ngoài ra, chế độ xem không đồng bộ sẽ mang lại hiệu quả thực thi và cho phép các yêu cầu khác được xử lý trong khi các tác vụ không đồng bộ được xử lý, cho phép nhiều yêu cầu hơn được xử lý bởi cùng một quy trình trong một khoảng thời gian cụ thể.

Cuối cùng, một phản hồi được trả lại để cho người dùng biết rằng bữa ăn BBQ ngon của họ đã sẵn sàng.

Tuyệt quá. Lưu tệp, sau đó quay lại trình duyệt của bạn và điều hướng đến http: // localhost: 8000 / khói_some_meats / . Sẽ mất vài giây để nhận được phản hồi:

Smoked 6 meats with Sweet Baby Ray's!

Trong bảng điều khiển của mình, bạn sẽ thấy:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Smoking some ribs...
Applying the Stubb's Original...
Ribs smoked.
Smoking some brisket...
Applying the Stubb's Original...
Brisket smoked.
Smoking some lemon chicken...
Applying the Stubb's Original...
Lemon chicken smoked.
Smoking some salmon...
Applying the Stubb's Original...
Salmon smoked.
Smoking some bison sirloin...
Applying the Stubb's Original...
Bison sirloin smoked.
Smoking some sausage...
Applying the Stubb's Original...
Sausage smoked.
INFO:     127.0.0.1:57501 - "GET /smoke_some_meats/ HTTP/1.1" 200 OK

Hãy lưu ý thứ tự của các câu lệnh in sau:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Đây là sự không đồng bộ khi làm việc: Khi get_smokableshàm ở chế độ ngủ, get_flavorhàm sẽ kết thúc quá trình xử lý.

Thịt cháy

Đồng bộ hóa cuộc gọi

Hỏi: Điều gì sẽ xảy ra nếu bạn thực hiện cuộc gọi đồng bộ bên trong chế độ xem không đồng bộ?

Điều tương tự sẽ xảy ra nếu bạn gọi một hàm không đồng bộ từ một chế độ xem không đồng bộ.

--

Để minh họa điều này, hãy tạo một hàm trợ giúp mới trong views.py của bạn được gọi là oversmoke:

# hello_async/views.py

def oversmoke() -> None:
    """ If it's not dry, it must be uncooked """
    sleep(5)
    print("Who doesn't love burnt meats?")

Rất đơn giản: Chúng tôi chỉ đợi đồng bộ trong năm giây.

Tạo dạng xem gọi hàm này:

# hello_async/views.py

async def burn_some_meats(request):
    oversmoke()
    return HttpResponse(f"Burned some meats.")

Cuối cùng, sắp xếp lộ trình trong URLconf của dự án của bạn:

# hello_async/urls.py

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

from hello_async.views import index, async_view, sync_view, smoke_some_meats, burn_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Truy cập tuyến đường trong trình duyệt tại http: // localhost: 8000 / burn_some_meats :

Burned some meats.

Lưu ý rằng phải mất năm giây để cuối cùng nhận được phản hồi từ trình duyệt. Bạn cũng nên nhận được đầu ra bảng điều khiển cùng một lúc:

Who doesn't love burnt meats?
INFO:     127.0.0.1:40682 - "GET /burn_some_meats HTTP/1.1" 200 OK

Có thể đáng lưu ý rằng điều tương tự sẽ xảy ra bất kể máy chủ bạn đang sử dụng, có thể là WSGI hoặc dựa trên ASGI.

Đồng bộ hóa và không đồng bộ hóa cuộc gọi

Hỏi: Điều gì sẽ xảy ra nếu bạn thực hiện một cuộc gọi đồng bộ và không đồng bộ bên trong một chế độ xem không đồng bộ?

Đừng làm điều này.

Chế độ xem đồng bộ và không đồng bộ có xu hướng hoạt động tốt nhất cho các mục đích khác nhau. Nếu bạn có chức năng chặn trong chế độ xem không đồng bộ, thì tốt nhất nó sẽ không tốt hơn là chỉ sử dụng chế độ xem đồng bộ.

Đồng bộ với không đồng bộ

Nếu bạn cần thực hiện cuộc gọi đồng bộ bên trong dạng xem không đồng bộ (ví dụ như tương tác với cơ sở dữ liệu thông qua Django ORM), hãy sử dụng sync_to_async làm trình bao bọc hoặc trình trang trí.

Thí dụ:

# hello_async/views.py

async def async_with_sync_view(request):
    loop = asyncio.get_event_loop()
    async_function = sync_to_async(http_call_sync, thread_sensitive=False)
    loop.create_task(async_function())
    return HttpResponse("Non-blocking HTTP request (via sync_to_async)")

Bạn có nhận thấy rằng chúng tôi đã đặt thread_sensitivethông số thành Falsekhông? Điều này có nghĩa là hàm đồng bộ http_call_sync, sẽ được chạy trong một luồng mới. Xem lại các tài liệu để biết thêm thông tin.

Thêm nhập vào đầu:

from asgiref.sync import sync_to_async

Thêm URL:

# hello_async/urls.py

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

from hello_async.views import (
    index,
    async_view,
    sync_view,
    smoke_some_meats,
    burn_some_meats,
    async_with_sync_view
)


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("sync_to_async/", async_with_sync_view),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Kiểm tra nó trong trình duyệt của bạn tại http: // localhost: 8000 / sync_to_async / .

Trong thiết bị đầu cuối của bạn, bạn sẽ thấy:

INFO:     127.0.0.1:61365 - "GET /sync_to_async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Bằng cách sử dụng sync_to_async, cuộc gọi đồng bộ chặn đã được xử lý trong một chuỗi nền, cho phép phản hồi HTTP được gửi lại trước cuộc gọi ngủ đầu tiên.

Chế độ xem cần tây và không đồng bộ

Q: Celery có còn cần thiết với các chế độ xem không đồng bộ của Django không?

Nó phụ thuộc.

Các chế độ xem không đồng bộ của Django cung cấp chức năng tương tự như một tác vụ hoặc hàng đợi tin nhắn mà không phức tạp. Nếu bạn đang sử dụng (hoặc đang cân nhắc) Django và muốn làm điều gì đó đơn giản (và không quan tâm đến độ tin cậy), chế độ xem không đồng bộ là một cách tuyệt vời để thực hiện điều này một cách nhanh chóng và dễ dàng. Nếu bạn cần thực hiện các quy trình nền chạy lâu và nặng hơn nhiều, bạn sẽ vẫn muốn sử dụng Celery hoặc RQ.

Cần lưu ý rằng để sử dụng các chế độ xem không đồng bộ một cách hiệu quả, bạn chỉ nên có các lệnh gọi không đồng bộ trong chế độ xem. Mặt khác, hàng đợi tác vụ sử dụng công nhân trên các quy trình riêng biệt và do đó có khả năng chạy các lệnh gọi đồng bộ trong nền, trên nhiều máy chủ.

Nhân tiện, bạn không phải chọn giữa chế độ xem không đồng bộ và hàng đợi tin nhắn - bạn có thể dễ dàng sử dụng chúng song song. Ví dụ: Bạn có thể sử dụng chế độ xem không đồng bộ để gửi email hoặc thực hiện sửa đổi cơ sở dữ liệu một lần, nhưng hãy yêu cầu Celery dọn dẹp cơ sở dữ liệu của bạn vào thời gian đã định mỗi đêm hoặc tạo và gửi báo cáo khách hàng.

Khi nào sử dụng

Đối với các dự án greenfield, nếu không đồng bộ là sở thích của bạn, hãy tận dụng các chế độ xem không đồng bộ và viết các quy trình I / O của bạn theo cách không đồng bộ càng nhiều càng tốt. Điều đó nói rằng, nếu hầu hết các chế độ xem của bạn chỉ cần thực hiện lệnh gọi đến cơ sở dữ liệu và thực hiện một số xử lý cơ bản trước khi trả lại dữ liệu, bạn sẽ không thấy sự gia tăng nhiều (nếu có) so với việc chỉ gắn bó với các chế độ xem đồng bộ.

Đối với các dự án brownfield, nếu bạn có ít hoặc không có quá trình I / O thì hãy gắn với chế độ xem đồng bộ. Nếu bạn có một số quy trình I / O, hãy kiểm tra xem bạn sẽ dễ dàng viết lại chúng theo cách không đồng bộ như thế nào. Viết lại I / O đồng bộ hóa thành không đồng bộ không dễ dàng, vì vậy có thể bạn sẽ muốn tối ưu hóa I / O đồng bộ hóa và chế độ xem của mình trước khi cố gắng viết lại thành không đồng bộ. Ngoài ra, không bao giờ là một ý tưởng hay khi kết hợp các quy trình đồng bộ hóa với các chế độ xem không đồng bộ của bạn.

Trong quá trình sản xuất, hãy đảm bảo sử dụng Gunicorn để quản lý Uvicorn nhằm tận dụng lợi thế của cả đồng thời (thông qua Uvicorn) và song song (thông qua Gunicorn worker):

gunicorn -w 3 -k uvicorn.workers.UvicornWorker hello_async.asgi:application

Sự kết luận

Tóm lại, mặc dù đây là một trường hợp sử dụng đơn giản, nhưng nó sẽ cung cấp cho bạn một ý tưởng sơ bộ về các khả năng mà các khung nhìn không đồng bộ của Django mở ra. Một số điều khác cần thử trong chế độ xem không đồng bộ của bạn là gửi email, gọi API của bên thứ ba và đọc / ghi vào tệp.

Nguồn:  https://testdriven.io

#django #async 

Ahebwe  Oscar

Ahebwe Oscar

1620185280

How model queries work in Django

How model queries work in Django

Welcome to my blog, hey everyone in this article we are going to be working with queries in Django so for any web app that you build your going to want to write a query so you can retrieve information from your database so in this article I’ll be showing you all the different ways that you can write queries and it should cover about 90% of the cases that you’ll have when you’re writing your code the other 10% depend on your specific use case you may have to get more complicated but for the most part what I cover in this article should be able to help you so let’s start with the model that I have I’ve already created it.

**Read More : **How to make Chatbot in Python.

Read More : Django Admin Full Customization step by step

let’s just get into this diagram that I made so in here:

django queries aboutDescribe each parameter in Django querset

we’re making a simple query for the myModel table so we want to pull out all the information in the database so we have this variable which is gonna hold a return value and we have our myModel models so this is simply the myModel model name so whatever you named your model just make sure you specify that and we’re gonna access the objects attribute once we get that object’s attribute we can simply use the all method and this will return all the information in the database so we’re gonna start with all and then we will go into getting single items filtering that data and go to our command prompt.

Here and we’ll actually start making our queries from here to do this let’s just go ahead and run** Python manage.py shell** and I am in my project file so make sure you’re in there when you start and what this does is it gives us an interactive shell to actually start working with our data so this is a lot like the Python shell but because we did manage.py it allows us to do things a Django way and actually query our database now open up the command prompt and let’s go ahead and start making our first queries.

#django #django model queries #django orm #django queries #django query #model django query #model query #query with django

Ananya Gupta

Ananya Gupta

1597123834

Main Pros and Cons of Django As A Web Framework for Python Developers

Django depicts itself as “the web system for fussbudgets with cutoff times”. It was intended to help Python engineers take applications from idea to consummation as fast as could be expected under the circumstances.

It permits fast turn of events on the off chance that you need to make a CRUD application with batteries included. With Django, you won’t need to rehash an already solved problem. It just works and lets you center around your business rationale and making something clients can utilize.

Pros of Django

“Batteries included” theory

The standard behind batteries-included methods normal usefulness for building web applications accompanies the system, not as isolated libraries.

Django incorporates much usefulness you can use to deal with normal web advancement undertakings. Here are some significant level functionalities that Django gives you, which else you need to stay together if you somehow happened to utilize a small scale structure:

ORM

Database relocations

Client validation

Administrator board

Structures

Normalized structure

Django as a system proposes the right structure of an undertaking. That structure helps designers in making sense of how and where to execute any new component.

With a generally acknowledged venture structure that is like numerous tasks, it is a lot simpler to discover online good arrangements or approach the network for help. There are numerous energetic Python designers who will assist you with comprehending any issue you may experience.

Django applications

Django applications (or applications for short) permit designers to separate a task into numerous applications. An application is whatever is introduced by putting in settings.INSTALLED_APPS. This makes it simpler for engineers to add usefulness to the web application by coordinating outer Django applications into the venture.

There are many reusable modules and applications to accelerate your turn of events learn through Online Django Class and Check the Django website.

Secure of course

Django gives great security assurance out of the crate and incorporates avoidance components for basic assaults like SQL Injection (XSS) and Cross-site Request Forgery (CSRF). You can discover more subtleties in the official security diagram control.

REST structure for building APIs

Django REST Framework, commonly condensed “DRF”, is a Python library for building APIs. It has secluded and adaptable engineering that functions admirably for both straightforward and complex web APIs.

DRF gives a lot of verification and authorization strategies out of the case. It is an adaptable, full-included library with measured and adjustable engineering. It accompanies nonexclusive classes for CRUD tasks and an implicit API program for testing API endpoints.

GraphQL structure for building APIs

Huge REST APIs regularly require a lot of solicitations to various endpoints to recover every single required datum. GraphQL it’s a question language that permits us to share related information in a lot simpler design. For a prologue to GraphQL and an outline of its ideas, if it’s not too much trouble allude to the authority GraphQL documentation.

Graphene-Django gives reflections that make it simple to add GraphQL usefulness to your Django venture. Ordinary Django models, structures, validation, consent arrangements, and different functionalities can be reused to manufacture GraphQL blueprint. It additionally gives an implicit API program for testing API endpoints.

Cons of Django

Django ORM

Django ORM, made before SQLAlchemy existed, is currently much sub-par compared to SQLAlchemy. It depends on the Active Record design which is more regrettable than the Unit of Work design embraced by SQLAlchemy. This implies, in Django, models can “spare” themselves and exchanges are off as a matter of course, they are a bit of hindsight. Peruse more in Why I kind of aversion Django.

Django advances course popularity increses day by day:

Django is huge and is viewed as strong bit of programming. This permits the network to create several reusable modules and applications yet has additionally restricted the speed of advancement of the Django. On head of that Django needs to keep up in reverse similarity, so it advances gradually.

Rundown - Should I use Django as a Python designer?

While Django ORM isn’t as adaptable as SQLAlchemy and the enormous environment of reusable modules and applications hinders structure advancement - plainly Django ought to be the best option web system for Python engineers.

Elective, light systems, similar to Flask, while offering a retreat from Django huge biological system and designs, in the long haul can require substantially more additional libraries and usefulness, in the end making many experienced Python engineers winding up wishing they’d began with Django.

Django undertaking’s security and network have become enormously over the previous decade since the system’s creation. Official documentation and instructional exercises are probably the best anyplace in programming advancement. With each delivery, Django keeps on including huge new usefulness.

#django online training #django online course #online django course #django course #django training #django certification course

Marget D

Marget D

1626077187

4 key Features of Django Framework that Make it the Best Amongst all!

Django is one of the popular python based open-source web frameworks mainly used by the developers who like to have rapid development along with the clean pragmatic design.

Read this blog to know the various Django Features with details.

#django framework #django web development #django development company #django development services #python django development company #python django development