Se, de acordo com o relatório de Artyom Malyshev (
proofit404 ), eles fizerem um filme, o diretor será Quentin Tarantino - ele já fez um filme sobre Django, e também o segundo. Todos os detalhes da vida útil dos mecanismos internos do Django, desde o primeiro byte da solicitação HTTP até o último byte da resposta. A extravagância de formas de analisador, compilação de SQL cheia de ação, efeitos especiais da implementação do mecanismo de modelo para HTML. Quem está gerenciando o pool de conexões e como? Tudo isso em ordem cronológica de processamento de objetos WSGI. Em todas as telas do país - a decodificação "Django sob microscópio".
Sobre o palestrante: Artyom Malyshev é o fundador do projeto Dry Python e o desenvolvedor principal do Django Channels versão 1.0. Ele escreve Python há 5 anos e ajudou a organizar reuniões do Python Rannts em Nizhny Novgorod. Artyom pode ser familiar para você sob o apelido
PROOFIT404 . A apresentação do relatório é armazenada
aqui .
Era uma vez, lançamos a versão antiga do Django. Então ela parecia assustadora e triste.

Eles viram que o
self_check
passou, instalamos tudo corretamente, tudo funcionou e agora você pode escrever código. Para conseguir tudo isso, tivemos que executar o
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.
O processo inicia, processa solicitações HTTP e toda a mágica acontece dentro e todo o código que queremos mostrar aos usuários como um site é executado.
Instalação
django-admin
aparece no sistema quando instalamos o Django usando, por exemplo,
pip, o gerenciador de pacotes .
$ pip install Django
entry_points setuptools
, que aponta para a função
execute_from_command_line
. Esta função é um ponto de entrada para qualquer operação com o Django, para qualquer processo atual.
Bootstrap
O que acontece dentro de uma função?
Bootstrap , que é dividido em duas iterações.
Definir configurações
O primeiro é
ler configurações :
import django.conf.global_settings import_module(os.environ["DJANGO_SETTINGS_MODULE"])
As configurações padrão
global_settings
, a partir da variável de ambiente, tentamos encontrar o módulo com
DJANGO_SETTINGS_MODULE
, que o usuário escreveu. Essas configurações são combinadas em um espaço para nome.
Qualquer um que escreve no Django pelo menos “Olá, mundo” sabe que existe
INSTALLED_APPS
- onde escrevemos o código do usuário.
Preencher aplicativos
Na segunda parte, todos esses aplicativos, essencialmente pacotes, são iterados um por um. Criamos para cada configuração, importamos modelos para trabalhar com um banco de dados e verificamos a integridade dos modelos. Além disso, a estrutura executa
Check
, ou seja, verifica se cada modelo possui uma chave primária, todas as chaves estrangeiras apontam para os campos existentes e se o campo Null não está gravado no BooleanField, mas o NullBooleanField é usado.
for entry in settings.INSTALLED_APPS: cfg = AppConfig.create(entry) cfg.import_models()
Esta é a verificação mínima de sanidade para modelos, para o painel de administração, para qualquer coisa - sem conectar ao banco de dados, sem algo super complicado e específico. Nesta fase, o Django ainda não sabe qual comando você pediu para executar, ou seja, não distingue
migrate
do
runserver
ou
shell
.
Então nos encontramos em um módulo que tenta adivinhar, por argumentos da linha de comando, qual comando queremos executar e em qual aplicativo ele se encontra.
Comando de gerenciamento
Nesse caso, o módulo runserver terá um módulo
django.core.management.commands.runserver
interno. Depois de importar o módulo, por convenção, a classe global
Command
é chamada dentro, é instanciada e dizemos: "
Encontrei você, aqui você tem os argumentos da linha de comando que o usuário passou, faça algo com eles ".
Em seguida, vamos ao módulo runserver e vemos que o
Django é feito de "regexp and sticks" , sobre o qual falarei em detalhes hoje:
Comandos
Role uma tela e meia - finalmente chegamos à definição de nossa equipe que inicia o servidor.
BaseCommand
executa um conjunto mínimo de operações para que os argumentos da linha de comando resultem em argumentos para chamar as funções de
**options
*args
e
**options
. Vemos que a instância do servidor WSGI está sendo criada aqui, o WSGIHandler global está instalado neste servidor WSGI - este é exatamente o
God Object Django . Podemos dizer que esta é a única instância do framework. A instância é instalada no servidor globalmente - através do
set application
e diz: "Gire no loop de eventos, execute solicitações".
Sempre há um loop de eventos em algum lugar e um programador que lhe dá tarefas.
Servidor WSGI
O que é o
WSGIHandler ? O WSGI é uma interface que permite processar solicitações HTTP com um nível mínimo de abstração e se parece com algo na forma de uma função.
Manipulador WSGI
Por exemplo, aqui está uma instância de uma classe que possui uma
call
definida. Ele espera pela entrada do dicionário, na qual os cabeçalhos serão apresentados como bytes e como manipulador de arquivos. O manipulador é necessário para ler o
<body>
solicitação. O próprio servidor também fornece retorno de chamada
start_response
para que possamos enviar
response.headers
e seu cabeçalho, por exemplo, status, em um pacote.
Além disso, podemos passar o corpo da resposta para o servidor através do objeto de resposta.
A resposta é um gerador sobre o qual você pode iterar.
Todos os servidores escritos para WSGI - Gunicorn, uWSGI, Waitress, trabalham nessa interface e são intercambiáveis. Agora estamos considerando um servidor para desenvolvimento, mas qualquer servidor chega ao ponto em que no Django ele atravessa o ambiente e o retorno de chamada.
O que há dentro de Deus Object?
O que acontece dentro dessa função global de Objeto Deus dentro do Django?
- PEDIDO.
- MIDDLEWARES.
- ROUTING para visualizar.
- VIEW - processamento de código do usuário dentro da view.
- FORMULÁRIO - trabalhe com formulários.
- ORM.
- MODELO
- RESPOSTA.
Todo o maquinário que queremos do Django ocorre em uma única função, que está espalhada por toda a estrutura.
Pedido
Nós agrupamos o ambiente WSGI, que é um dicionário simples, em algum objeto especial, para a conveniência de trabalhar com o ambiente. Por exemplo, é mais conveniente descobrir a duração de uma solicitação do usuário trabalhando com algo semelhante a um dicionário do que com uma sequência de bytes que precisa ser analisada e procurar por entradas de valor-chave. Ao trabalhar com cookies, também não quero calcular manualmente se o período de armazenamento expirou ou não e de alguma forma interpretá-lo.
A solicitação contém analisadores, bem como um conjunto de manipuladores para controlar o processamento do corpo da solicitação POST: se é um arquivo na memória ou temporário no armazenamento em disco. Tudo é decidido dentro da solicitação. A requisição no Django também é um objeto agregador no qual todos os middlewares podem colocar as informações necessárias sobre a sessão, autenticação e autorização do usuário. Podemos dizer que este também é um Objeto Divino, mas menor.
Solicitação adicional chega ao middleware.
Middlewares
Middleware é um invólucro que envolve outras funções como um decorador. Antes de abrir mão do controle do middleware, no método de chamada, respondemos ou chamamos um middleware já empacotado.
É assim que o middleware se parece do ponto de vista de um programador.
Configurações
Definir
class Middleware: def __init__(self, get_response=None): self.get_response = get_response def __call__(self, request): return self.get_response(request)
Do ponto de vista do Django, os middlewares parecem uma espécie de pilha:
Aplicar
def get_response(self, request): set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) return response
Pegamos a função
get_response
inicial, envolvemos-a em um manipulador, que traduzirá, por exemplo,
permission error
e
permission error
not found error
no código HTTP correto. Envolvemos tudo no middleware em si da lista. A pilha de middlewares cresce e cada próxima envolve a anterior. Isso é muito semelhante à aplicação da mesma pilha de decoradores em todas as visualizações de um projeto, apenas centralmente. Não há necessidade de sair e organizar os invólucros com as mãos de acordo com o projeto, tudo é conveniente e lógico.
Passamos por 7 círculos de middlewares, nossa solicitação sobreviveu e decidimos processá-la à vista. Além disso, chegamos ao módulo de roteamento.
Encaminhamento
É aqui que decidimos qual manipulador solicitar uma solicitação específica. E isso está resolvido:
- com base no URL;
- na especificação WSGI, em que request.path_info é chamado.
URLs
Pegamos o resolvedor, alimentamos o URL de solicitação atual e esperamos que ele retorne a função view, e a partir do mesmo URL obteremos os argumentos com os quais chamar o view. Então,
get_response
chama a visualização, lida com exceções e faz algo com ela.
Resolver
É assim que o resolvedor se parece:
Isso também é regexp, mas recursivo. Ele entra em partes do URL, procura o que o usuário deseja: outros usuários, postagens, blogs ou é algum tipo de conversor, por exemplo, um ano específico que precisa ser resolvido, colocado em argumentos, convertido em int.
É característico que a profundidade da recursão do método de resolução seja sempre igual ao número de argumentos com os quais a exibição é chamada. Se algo deu errado e não encontramos um URL específico, ocorre um erro não encontrado.
Então finalmente chegamos à vista - o código que o programador escreveu.
Ver
Em sua representação mais simples, é uma função que retorna solicitação de resposta, mas dentro dela realizamos tarefas lógicas: “para, se algum dia” - muitas tarefas repetitivas. O Django nos fornece uma visão baseada em classe, onde você pode especificar detalhes específicos, e todo o comportamento será interpretado no formato correto pela própria classe.
Fluxograma do método
self.dispatch() self.post() self.get_form() self.form_valid() self.render_to_response()
O método de
dispatch
desta instância já está no mapeamento de URL em vez de em uma função. A expedição baseada no verbo HTTP entende qual método chamar: O POST chegou até nós e provavelmente queremos instanciar o objeto do formulário, se o formulário for válido, salve-o no banco de dados e mostre o modelo. Tudo isso é feito através do grande número de mixins que compõem essa classe.
Formulário
O formulário deve ser lido no soquete antes de entrar na visualização do Django - através do mesmo manipulador de arquivos que se encontra no ambiente WSGI. form-data é um fluxo de bytes, no qual os separadores são descritos - podemos ler esses blocos e fazer algo deles. Pode ser uma correspondência de valor-chave, se for um campo, parte de um arquivo e, novamente, algum campo - tudo está misturado.
Content-Type: multipart/form-data;boundary="boundary" --boundary name="field1" value1 --boundary name="field2"; value2
Analisador
O analisador consiste em 3 partes.
O iterador de partes que cria as leituras esperadas do fluxo de bytes se transforma em um iterador que pode produzir
boundaries
. Garante que, se algo retornar, será um limite. Isso é necessário para que, dentro do analisador, não seja necessário armazenar o estado da conexão, ler do soquete ou não ler para minimizar a lógica do processamento de dados.
Em seguida, o gerador envolve o
LazyStream , que novamente cria um arquivo de objeto, mas com a leitura esperada. Portanto, o analisador já pode percorrer pedaços de bytes e criar um valor-chave a partir deles.
campo e dados aqui sempre serão strings . Se recebermos um horário de dados no formato ISO, o formulário do Django (que foi escrito pelo programador) receberá, usando certos campos, por exemplo, carimbo de data / hora.
Além disso, o formulário, provavelmente, quer se salvar em um banco de dados, e aqui o Django ORM começa.
ORM
Aproximadamente através desses pedidos DSL para ORM são executados:
Usando chaves, você pode coletar expressões SQL semelhantes:
SELECT * WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
Como está indo isso?
Queryset
O método de
exclude
tem um objeto de
Query
sob o capô. O objeto passa argumentos para a função e cria uma hierarquia de objetos, cada um dos quais pode se transformar em uma parte separada da consulta SQL como uma sequência.
Ao percorrer a árvore, cada uma das seções pesquisa seus nós filhos, recebe consultas SQL aninhadas e, como resultado, podemos construir o SQL como uma string. Por exemplo, o valor-chave não será um campo SQL separado, mas será comparado com o valor-valor. A concatenação e a negação de consultas funcionam da mesma maneira que uma passagem de árvore recursiva, para cada nó do qual uma conversão ao SQL é chamada.
Compilador
Saída
>>> Q(headline='Hello')
Um pequeno compilador auxiliar é passado para esse método, que pode distinguir o dialeto do MySQL do PostgreSQL e organizar corretamente o açúcar sintático usado no dialeto de um banco de dados específico.
Roteamento de banco de dados
Quando recebemos a consulta SQL, o modelo bate no roteamento de banco de dados e pergunta em qual banco de dados ele está. Em 99% dos casos, será o banco de dados padrão, nos 1% restantes - algum tipo próprio.
O agrupamento de um driver de banco de dados de uma interface específica da biblioteca, como Python MySQL ou Psycopg2, cria um objeto universal com o qual o Django pode trabalhar. Há um invólucro para cursores, um invólucro para transações.
Piscina de conexão
Nesta conexão em particular, enviamos solicitações para o soquete que está batendo no banco de dados e aguardamos a execução. O wrapper da biblioteca lerá a resposta humana do banco de dados na forma de um registro, e o Django coleta a instância do modelo desses dados nos tipos Python. Esta não é uma iteração complicada.
Escrevemos algo no banco de dados, lemos algo e decidimos contar ao usuário sobre ele usando a página HTML. Para fazer isso, o Django tem uma linguagem de modelo não-apreciada pela comunidade que se parece com uma linguagem de programação, apenas em um arquivo HTML.
Template
from django.template.loader import render_to_string render_to_string('my_template.html', {'entries': ...})
Código
<ul> {% for entry in entries %} <li>{{ entry.name }}</li> {% endfor %} </ul>
Analisador
Surpresa - regexp novamente. Somente no final deve haver uma vírgula, e a lista será muito abaixo. Este é provavelmente o regexp mais difícil que eu já vi neste projeto.
Lexer
O manipulador e o intérprete de modelos são bastante simples. Existe um lexer que usa o regexp para traduzir o texto em uma lista de pequenos tokens.
Repetimos a lista de fichas, veja: “Quem é você? Envolva você em um nó de tag. ” Por exemplo, se este é o início de alguns
if
ou
for
ou
for
, o manipulador de tags usará o manipulador apropriado. O manipulador
for
novamente diz ao analisador: "Leia-me uma lista de tokens até a tag de fechamento".
A operação vai para o analisador novamente.
Um nó, tag e analisador são coisas mutuamente recursivas, e a profundidade da recursão geralmente é igual ao aninhamento do próprio modelo por tags.
Analisador
def parse(): while tokens: token = tokens.pop() if token.startswith(BLOCK_TAG_START): yield TagNode(token) elif token.startswith(VARIABLE_TAG_START): ...
O manipulador de tags nos fornece um nó específico, por exemplo, com um loop for, para o qual o método
render
aparece.
For loop
Para o nó
class ForNode(Node): def render(self, context): with context.push(): for i in self.args: yield self.body.render(context)
O método de
render
é uma árvore de renderização. Cada nó superior pode ir para um nó filha, pedir para ela renderizar. Os programadores estão acostumados a mostrar algumas variáveis neste modelo. Isso é feito através do
context
- é apresentado na forma de um dicionário regular. Esta é uma pilha de dicionários para emular um escopo quando inserimos uma tag. Por exemplo, se o próprio
context
alterar alguma outra tag dentro do loop
for
, quando sairmos do loop, as alterações serão revertidas. Isso é conveniente porque, quando tudo é global, é difícil trabalhar.
Resposta
Finalmente conseguimos nossa linha com a resposta HTTP:
Olá Mundo!
Podemos dar a linha ao usuário.
- Retorne esta resposta da vista.
- Exibir listas de middlewares.
- Middlewares essa resposta modifica, complementa e aprimora.
- A resposta começa a iterar dentro do WSGIHandler, é parcialmente gravada no soquete e o navegador recebe uma resposta do nosso servidor.
Todas as startups famosas que foram escritas no Django, como Bitbucket ou Instagram, começaram com um ciclo tão pequeno que todo programador passou.
Tudo isso, e uma apresentação no Moscow Python Conf ++, é necessário para você entender melhor o que está em suas mãos e como usá-lo. Em qualquer mágica, há uma grande parte do regexp que você deve poder cozinhar.
Artyom Malyshev e outros 23 grandes palestrantes em 5 de abril nos darão novamente muita reflexão e discussão sobre o tópico Python na conferência Moscow Python Conf ++ . Estude o cronograma e participe da troca de experiências na solução de vários problemas usando o Python.