Jika menurut laporan Artyom Malyshev (
proofit404 ) mereka akan membuat film, maka sutradara akan menjadi Quentin Tarantino - dia sudah membuat satu film tentang Django, dia juga akan merekam yang kedua. Semua detail dari kehidupan mekanisme internal Django dari byte pertama permintaan HTTP ke byte terakhir dari respons. The extravaganza bentuk parser, kompilasi penuh aksi dari SQL, efek khusus dari implementasi mesin template untuk HTML. Siapa yang mengelola kumpulan koneksi dan bagaimana? Semua ini dalam urutan kronologis pemrosesan objek WSGI. Di semua layar negara - decoding "Django di bawah mikroskop".
Tentang pembicara: Artyom Malyshev adalah pendiri proyek Dry Python dan pengembang inti dari Django Channels versi 1.0. Dia telah menulis Python selama 5 tahun dan telah membantu mengatur pertemuan Python Rannts di Nizhny Novgorod. Artyom mungkin tidak asing bagi Anda dengan nama panggilan
PROOFIT404 . Presentasi laporan disimpan di
sini .
Sekali waktu, kami meluncurkan versi lama Django. Kemudian dia tampak menakutkan dan sedih.

Mereka melihat
self_check
berlalu, kami memasang semuanya dengan benar, semuanya berfungsi dan sekarang Anda dapat menulis kode. Untuk mencapai semua ini, kami harus menjalankan
django-admin runserver
.
$ django-admin runserver Performing system checks⦠System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate1 to apply them. August 21, 2018 - 15:50:53 Django version 2.1, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/Quit the server with CONTROL-C.
Proses dimulai, memproses permintaan HTTP, dan semua keajaiban terjadi di dalam dan semua kode yang ingin kami tampilkan kepada pengguna saat situs dijalankan.
Instalasi
django-admin
muncul di sistem ketika kami menginstal Django menggunakan, misalnya,
pip, manajer paket .
$ pip install Django
entry_points setuptools
muncul, yang menunjuk ke fungsi
execute_from_command_line
. Fungsi ini adalah titik masuk untuk operasi apa pun dengan Django, untuk setiap proses saat ini.
Bootstrap
Apa yang terjadi di dalam suatu fungsi?
Bootstrap , yang terbagi menjadi dua iterasi.
Konfigurasikan pengaturan
Yang pertama adalah
membaca konfigurasi :
import django.conf.global_settings import_module(os.environ["DJANGO_SETTINGS_MODULE"])
Pengaturan default
global_settings
, kemudian dari variabel lingkungan kami mencoba menemukan modul dengan
DJANGO_SETTINGS_MODULE
, yang ditulis pengguna. Pengaturan ini digabungkan menjadi satu ruang nama.
Siapa pun yang menulis di Django setidaknya "Halo, dunia" tahu bahwa ada
INSTALLED_APPS
- tempat kami menulis kode pengguna.
Mengisi aplikasi
Pada bagian kedua, semua aplikasi ini, pada dasarnya paket, diulang satu per satu. Kami membuat untuk setiap Konfigurasi, kami mengimpor model untuk bekerja dengan database dan kami memeriksa model untuk integritas. Lebih jauh lagi, kerangka kerjanya menjalankan
Check
, yaitu, memeriksa bahwa setiap model memiliki kunci utama, semua kunci asing menunjuk ke bidang yang ada dan bahwa bidang Null tidak ditulis dalam BooleanField, tetapi NullBooleanField digunakan.
for entry in settings.INSTALLED_APPS: cfg = AppConfig.create(entry) cfg.import_models()
Ini adalah pemeriksaan kewarasan minimum untuk model, untuk panel admin, untuk apa saja - tanpa terhubung ke database, tanpa sesuatu yang sangat rumit dan spesifik. Pada tahap ini, Django belum tahu perintah mana yang Anda minta untuk dieksekusi, yaitu, tidak membedakan
migrate
dari
runserver
atau
shell
.
Kemudian kita menemukan diri kita dalam modul yang mencoba menebak dengan argumen baris perintah perintah mana yang ingin kita jalankan dan di mana aplikasi itu berada.
Perintah manajemen
Dalam hal ini, modul runserver akan memiliki modul
django.core.management.commands.runserver
. Setelah mengimpor modul, dengan konvensi,
Command
kelas global dipanggil di dalam, dipakai, dan kami berkata: "
Saya menemukan Anda, di sini Anda memiliki argumen baris perintah yang dilewati pengguna, melakukan sesuatu dengan mereka ."
Selanjutnya, kita pergi ke modul runserver dan melihat bahwa
Django terbuat dari "regexp and sticks" , yang akan saya bicarakan secara rinci hari ini:
Perintah
Gulir ke bawah satu setengah layar - akhirnya kita masuk ke definisi tim kami yang memulai server.
BaseCommand
melakukan serangkaian operasi minimal agar argumen baris perintah menghasilkan argumen untuk memanggil fungsi
*args
dan
**options
. Kita melihat bahwa instance server WSGI sedang dibuat di sini, WSGIHandler global diinstal di server WSGI ini - ini persisnya
God Object Django . Kita dapat mengatakan bahwa ini adalah satu-satunya contoh kerangka kerja. Instance diinstal pada server secara global - melalui
set application
dan mengatakan: "Putar di Event Loop, jalankan permintaan."
Selalu ada Perulangan Acara di suatu tempat dan seorang programmer yang memberinya tugas.
Server WSGI
Apa itu
WSGIHandler ? WSGI adalah antarmuka yang memungkinkan Anda untuk memproses permintaan HTTP dengan tingkat abstraksi minimum, dan terlihat seperti sesuatu dalam bentuk fungsi.
Handler WSGI
Sebagai contoh, ini adalah instance dari kelas yang memiliki
call
ditentukan. Dia menunggu entri kamusnya, di mana header akan disajikan sebagai byte dan file-handler. Handler diperlukan untuk membaca
<body>
permintaan. Server itu sendiri juga memberikan callback
start_response
sehingga kami dapat mengirim
response.headers
dan header-nya, misalnya, status, dalam satu bundel.
Lebih lanjut, kita bisa meneruskan tubuh respons ke server melalui objek respons.
Respons adalah generator yang bisa Anda ulangi.
Semua server yang ditulis untuk WSGI - Gunicorn, uWSGI, Waitress, bekerja pada antarmuka ini dan dapat dipertukarkan. Kami sekarang mempertimbangkan server untuk pengembangan, tetapi server mana pun sampai pada titik di Django itu mengetuk lingkungan dan panggilan balik.
Apa yang ada di dalam Objek Tuhan?
Apa yang terjadi di dalam fungsi Objek Dewa global ini di dalam Django?
- PERMINTAAN.
- MIDDLEWARES.
- Permintaan ROUTING untuk melihat.
- LIHAT - pemrosesan kode pengguna tampilan dalam.
- BENTUK - bekerja dengan formulir.
- ORM.
- TEMPLATE
- TANGGAPAN.
Semua mesin yang kita inginkan dari Django berlangsung dalam satu fungsi, yang tersebar di seluruh kerangka kerja.
Minta
Kami membungkus lingkungan WSGI, yang merupakan kamus sederhana, di beberapa objek khusus, untuk kenyamanan bekerja dengan lingkungan. Misalnya, lebih mudah untuk mengetahui panjang permintaan pengguna melalui bekerja dengan sesuatu yang mirip dengan kamus daripada dengan string byte yang perlu diuraikan dan mencari entri nilai kunci di dalamnya. Saat bekerja dengan cookie, saya juga tidak ingin menghitung secara manual apakah periode penyimpanan telah kedaluwarsa atau belum, dan entah bagaimana menafsirkannya.
Permintaan berisi parser, serta satu set penangan untuk mengontrol pemrosesan tubuh permintaan POST: apakah itu file dalam memori atau sementara dalam penyimpanan pada disk. Semuanya diputuskan di dalam Permintaan. Permintaan di Django juga merupakan objek agregator di mana semua middlewares dapat menaruh informasi yang kita butuhkan tentang sesi, otentikasi, dan otorisasi pengguna. Kita dapat mengatakan bahwa ini juga merupakan Obyek Tuhan, tetapi lebih kecil.
Permintaan Lebih Lanjut sampai ke middleware.
Middlewares
Middleware adalah pembungkus yang membungkus fungsi lain seperti dekorator. Sebelum melepaskan kendali middleware, dalam metode panggilan kami memberikan respons atau memanggil middleware yang sudah dibungkus.
Inilah yang tampak seperti middleware dari sudut pandang programmer.
Pengaturan
Tentukan
class Middleware: def __init__(self, get_response=None): self.get_response = get_response def __call__(self, request): return self.get_response(request)
Dari sudut pandang Django, middlewares terlihat seperti tumpukan:
Terapkan
def get_response(self, request): set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) return response
Kami mengambil fungsi
get_response
awal, membungkusnya dengan handler, yang akan menerjemahkan, misalnya,
permission error
dan
not found error
ke dalam kode HTTP yang benar. Kami membungkus semuanya dalam middleware itu sendiri dari daftar. Tumpukan middlewares tumbuh, dan masing-masing berikutnya membungkus yang sebelumnya. Ini sangat mirip dengan menerapkan tumpukan dekorator yang sama untuk semua tampilan dalam suatu proyek, hanya secara terpusat. Tidak perlu berkeliling dan mengatur pembungkus dengan tangan Anda sesuai dengan proyek, semuanya nyaman dan logis.
Kami melewati 7 lingkaran middlewares, permintaan kami bertahan dan memutuskan untuk memprosesnya. Selanjutnya kita sampai pada modul routing.
Routing
Di sinilah kami memutuskan penangan mana yang akan dipanggil untuk permintaan tertentu. Dan ini diselesaikan:
- berdasarkan url;
- dalam spesifikasi WSGI, di mana request.path_info dipanggil.
Url
Kami mengambil resolver, memberi makan url permintaan saat ini dan mengharapkannya untuk mengembalikan fungsi tampilan itu sendiri, dan dari url yang sama kami mendapatkan argumen yang dapat digunakan untuk memanggil tampilan. Kemudian
get_response
panggilan tampilan, menangani pengecualian dan melakukan sesuatu dengannya.
Penyelesai
Beginilah bentuk resolver:
Ini juga regexp, tetapi rekursif. Ini masuk di bagian url, mencari apa yang diinginkan pengguna: pengguna lain, posting, blog, atau semacam konverter, misalnya, tahun tertentu yang perlu diselesaikan, dimasukkan ke dalam argumen, dilemparkan ke argumen, dilemparkan ke int.
Merupakan karakteristik bahwa kedalaman rekursi dari metode tekad selalu sama dengan jumlah argumen yang disebut tampilan. Jika terjadi kesalahan dan kami tidak menemukan url tertentu, kesalahan tidak ditemukan terjadi.
Lalu kami akhirnya melihat - kode yang ditulis oleh programmer.
Lihat
Dalam representasi yang paling sederhana, ini adalah fungsi yang mengembalikan permintaan dari respons, tetapi di dalamnya kami melakukan tugas-tugas logis: "untuk, jika, suatu hari" - banyak tugas berulang. Django memberi kami tampilan berbasis kelas di mana Anda dapat menentukan detail spesifik, dan semua perilaku akan ditafsirkan dalam format yang benar oleh kelas itu sendiri.
Bagan alur metode
self.dispatch() self.post() self.get_form() self.form_valid() self.render_to_response()
Metode
dispatch
instance ini sudah dalam pemetaan url alih-alih fungsi. Pengiriman berdasarkan kata kerja HTTP mengerti metode mana yang harus dihubungi: POST datang kepada kami dan kami kemungkinan besar ingin instantiate objek form, jika form valid, simpan ke database dan perlihatkan templat. Ini semua dilakukan melalui sejumlah besar mixin yang membentuk kelas ini.
Formulir
Formulir harus dibaca dari soket sebelum masuk ke tampilan Django - melalui penangan file yang sama yang terletak di lingkungan WSGI. form-data adalah aliran byte, di mana pemisah dijelaskan - kita dapat membaca blok ini dan membuat sesuatu darinya. Ini bisa menjadi korespondensi nilai kunci, jika itu adalah bidang, bagian dari file, lalu lagi beberapa bidang - semuanya dicampur.
Content-Type: multipart/form-data;boundary="boundary" --boundary name="field1" value1 --boundary name="field2"; value2
Parser
Parser terdiri dari 3 bagian.
Chunk iterator yang menciptakan pembacaan yang diharapkan dari aliran byte berubah menjadi iterator yang dapat menghasilkan
boundaries
. Ini menjamin bahwa jika sesuatu kembali, itu akan menjadi batas. Hal ini diperlukan agar di dalam pengurai tidak perlu menyimpan keadaan koneksi, membaca dari soket atau tidak membaca untuk meminimalkan logika pemrosesan data.
Selanjutnya, generator membungkus di
LazyStream , yang lagi-lagi membuat file objek dari itu, tetapi dengan pembacaan yang diharapkan. Jadi parser sudah bisa berjalan melalui potongan-potongan byte dan membangun nilai kunci dari mereka.
bidang dan data di sini akan selalu berupa string . Jika kami menerima datatime dalam format ISO, formulir Django (yang ditulis oleh programmer) akan menerima, menggunakan bidang-bidang tertentu, misalnya cap waktu.
Lebih jauh, bentuknya, kemungkinan besar, ingin menyimpan dirinya sendiri dalam basis data, dan di sini Django ORM dimulai.
ORM
Sekitar melalui permintaan DSL untuk ORM dijalankan:
Menggunakan kunci, Anda dapat mengumpulkan ekspresi SQL yang serupa:
SELECT * WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
Bagaimana kabarnya?
Queryset
Metode
exclude
memiliki objek
Query
bawah tenda. Objek dilewatkan argumen ke fungsi, dan itu menciptakan hirarki objek, yang masing-masing dapat mengubah dirinya menjadi bagian terpisah dari permintaan SQL sebagai string.
Ketika melintasi pohon, masing-masing bagian melakukan polling pada node anaknya, menerima query SQL yang bersarang, dan sebagai hasilnya, kita dapat membangun SQL sebagai string. Sebagai contoh, nilai-kunci tidak akan menjadi bidang SQL yang terpisah, tetapi akan dibandingkan dengan nilai-nilai. Gabungan dan penolakan query bekerja dengan cara yang sama dengan traversal pohon rekursif, untuk setiap node yang disebut sebagai pemeran SQL.
Kompiler
Keluaran
>>> Q(headline='Hello')
Kompiler pembantu kecil dilewatkan ke metode ini, yang dapat membedakan dialek MySQL dari PostgreSQL dan mengatur gula sintaksis yang digunakan dalam dialek database tertentu dengan benar.
Routing DB
Ketika kami menerima permintaan SQL, model mengetuk pada perutean DB dan menanyakan basis data yang mana. Dalam 99% kasus, ini akan menjadi basis data default, sisanya 1% - semacam miliknya sendiri.
Membungkus driver basis data dari antarmuka pustaka tertentu, seperti Python MySQL atau Psycopg2, menciptakan objek universal yang dapat digunakan Django. Ada pembungkus untuk kursor, pembungkus untuk transaksi.
Kolam renang penghubung
Dalam koneksi khusus ini, kami mengirim permintaan ke soket yang mengetuk database dan menunggu eksekusi. Pembungkus perpustakaan akan membaca respon manusia dari database dalam bentuk catatan, dan Django mengumpulkan contoh model dari data ini dalam tipe Python. Ini bukan iterasi yang rumit.
Kami menulis sesuatu ke dalam basis data, membaca sesuatu, dan memutuskan untuk memberi tahu pengguna tentang hal itu menggunakan halaman HTML. Untuk melakukan ini, Django memiliki bahasa templat yang tidak disukai komunitas yang terlihat seperti bahasa pemrograman, hanya dalam file HTML.
Templat
from django.template.loader import render_to_string render_to_string('my_template.html', {'entries': ...})
Kode
<ul> {% for entry in entries %} <li>{{ entry.name }}</li> {% endfor %} </ul>
Parser
Kejutan - regexp lagi. Hanya pada bagian akhir harus ada koma, dan daftar akan jauh ke bawah. Ini mungkin regexp paling sulit yang pernah saya lihat dalam proyek ini.
Lexer
Handler template dan interpreter sangat sederhana. Ada lexer yang menggunakan regexp untuk menerjemahkan teks ke dalam daftar token kecil.
Kami beralih ke daftar token, lihat: "Siapa kamu? Membungkus Anda dalam simpul tag. " Misalnya, jika ini adalah awal dari beberapa
if
atau
for
atau
for
, penangan tag akan mengambil penangan yang sesuai. For handler itu sendiri memberi tahu parser: "Baca saya daftar token sampai ke tag penutup."
Operasi kembali ke parser.
Node, tag, dan parser adalah hal yang saling rekursif, dan kedalaman rekursi biasanya sama dengan bersarangnya template itu sendiri dengan tag.
Parser
def parse(): while tokens: token = tokens.pop() if token.startswith(BLOCK_TAG_START): yield TagNode(token) elif token.startswith(VARIABLE_TAG_START): ...
Penangan tag memberi kita simpul tertentu, misalnya, dengan loop for, yang muncul metode
render
.
Untuk loop
Untuk simpul
class ForNode(Node): def render(self, context): with context.push(): for i in self.args: yield self.body.render(context)
Metode
render
adalah pohon render. Setiap simpul atas dapat pergi ke simpul anak, memintanya untuk membuat. Pemrogram digunakan untuk menunjukkan beberapa variabel dalam templat ini. Ini dilakukan melalui
context
- disajikan dalam bentuk kamus reguler. Ini adalah tumpukan kamus untuk meniru lingkup ketika kita memasukkan tag. Misalnya, jika
context
sendiri mengubah beberapa tag lain di dalam loop
for
, maka ketika kita keluar dari loop perubahan akan dibatalkan. Ini nyaman karena ketika semuanya bersifat global, sulit untuk bekerja.
Tanggapan
Akhirnya, kami mendapat tanggapan dari respons HTTP:
Halo Dunia!
Kami dapat memberikan garis ke pengguna.
- Kembalikan respons ini dari tampilan.
- Lihat daftar middlewares.
- Middlewares menanggapi, memodifikasi, melengkapi, dan meningkatkan ini.
- Respons mulai beralih di dalam WSGIHandler, sebagian ditulis ke soket, dan browser menerima respons dari server kami.
Semua startup terkenal yang ditulis dalam Django, seperti Bitbucket atau Instagram, dimulai dengan siklus kecil yang dilalui setiap programmer.
Semua ini, dan presentasi di Moscow Python Conf ++, perlu bagi Anda untuk lebih memahami apa yang ada di tangan Anda dan bagaimana menggunakannya. Dalam sihir apa pun, ada sebagian besar regexp yang harus Anda masak.
Artyom Malyshev dan 23 pembicara hebat lainnya pada tanggal 5 April akan kembali memberi kita banyak bahan untuk dipikirkan dan dibahas tentang topik Python pada konferensi Moskow Python Conf ++ . Pelajari jadwal dan bergabunglah dalam pertukaran pengalaman dalam menyelesaikan berbagai masalah menggunakan Python.