Pular para o conteúdo principal
BlogBancos de dadosComo Django faz o levantamento pesado para SQL

Como Django faz o levantamento pesado para SQL

Como Django Faz o Levantamento Pesado - Blog Header

Pythone especialmente o Django, são essenciais para construir aplicações mais eficientes, com menos código, e conectados a um banco de dados altamente escalonável. Estou aqui para falar com você sobre reduzir o atrito diário que vem com a construção e suporte de aplicações modernas usando SQL e Python para abstrair a complexidade e tornar nossos trabalhos e nossas vidas um pouco mais fáceis.

Sem entrar nas ervas daninhas, podemos assumir:

  • SQL é otimizado para bancos de dados SQL
  • Python não está otimizado para bancos de dados SQL

Este exercício suporta diretamente o ebook Understanding Databases e minha nova série educativa Linode LIVE! usando Python e ferramentas Pythonic para executar comandos em SQL bruto sem a necessidade de realmente escrever SQL. Estou usando a modelagem de dados do Django, mas a sintaxe é muito similar ao pacote SQLAlchemy em Python.

Vamos começar!
Aqui está um exemplo de um modelo de dados Django:

class BlogArticle(models.Model):
    user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
    title = models.CharField(max_length=120)
    slug = models.SlugField(blank=True, null=True)
    content = models.TextField(blank=True, null=True)
    publish_timestamp = models.DateTimeField(
        auto_now_add=False,
        auto_now=False,
        blank=True,
        null=True,
    )

Vamos assumir que este modelo vive em um aplicativo Django chamado Articles (As aplicações Django são essencialmente componentes que compõem a totalidade de um projeto Django).

Portanto, agora temos dois nomes para trabalhar:

  • Articles (nome do aplicativo)
  • BlogArticle (nome do modelo)

Em combinação, estes se traduzem no nome da Tabela SQL:

articles_blog_article

Django faz esta magia para nós.

Se estivéssemos usando a casca do MySQL, veríamos:

mysql> SHOW TABLES;
+------------------------------+
| Tables_in_cfe_django_blog_db |
+------------------------------+
| articles_blog_article        |
| auth_group                   |
| auth_group_permissions       |
| auth_permission              |
| auth_user                    |
| auth_user_groups             |
| auth_user_user_permissions   |
| django_admin_log             |
| django_content_type          |
| django_migrations            |
| django_session               |
+------------------------------+
11 rows in set (0.01 sec)

Agora vamos ver as colunas em nosso modelo Django:

mysql> DESCRIBE articles_blog_article;
+------------------------+--------------+------+-----+---------+----------------+
| Field                  | Type         | Null | Key | Default | Extra          |
+------------------------+--------------+------+-----+---------+----------------+
| id                     | bigint       | NO   | PRI | NULL    | auto_increment |
| title                  | varchar(120) | NO   |     | NULL    |                |
| slug                   | varchar(50)  | YES  | MUL | NULL    |                |
| content                | longtext     | YES  |     | NULL    |                |
| publish_timestamp      | datetime(6)  | YES  |     | NULL    |                |
| user_id                | int          | NO   | MUL | NULL    |                |
+------------------------+--------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)

Além de escrever uma configuração básica, Django fez todo o trabalho de SQL para nós neste banco de dados MySQL, e neste ponto, Django não fez nada muito impressionante. Na verdade, a maior parte deste exercício não foi projetado para destacar Django ou Python como um substituto do SQL, mas para lembrar o fato de que as abstrações funcionam.

A Ascensão de Python e o Custo do Atrito

Vamos falar sobre o caminho de menor resistência e por que acredito que Python é uma das melhores maneiras de alavancar o SQL.

É muito fácil de escrever, ler, correr e enviar Python. Mude "Python" para quase qualquer outro paradigma de programação e é quase impossível fazer a mesma afirmação. O JavaScripttambém é um concorrente, mas também é consistentemente confuso para Java. Entendo que estas são generalizações, e nem sempre são verdadeiras, mas são questões comuns que surgem ao desenvolver seu aplicativo.

Acredito que estas generalizações tendem a ser verdadeiras devido à sintaxe inglesa de fazer as coisas em Python.

Vamos comparar uma declaração SQL com uma declaração Python e Django:

  • SQL: SELECT * from articles_blog_article;
  • Python e Django: items = BlogArticle.objects.all()

Ambas as declarações produzem exatamente os mesmos dados. A declaração Python , entretanto, retorna uma lista de Python objetos (items) que quase qualquer desenvolvedor Python em toda uma gama de experiências pode utilizar. Os resultados do SQL bruto precisariam ser convertidos antes de serem usados em um aplicativo Python .

Descrições de campo
Se olharmos mais de perto esta descrição de campo SQL:

+------------------------+--------------+------+-----+---------+----------------+
| Field                  | Type         | Null | Key | Default | Extra          |
+------------------------+--------------+------+-----+---------+----------------+
| title                  | varchar(120) | NO   |     | NULL    |                |
+------------------------+--------------+------+-----+---------+----------------+

Versus esta descrição de campo Django:

title = models.CharField(max_length=120)

  • Qual deles tem mais atrito?
  • Qual deles é mais fácil de entender o que está acontecendo?

O que fornece apenas informações suficientes?

Se você não fosse um codificador e serrasse varchar(120)O que você acha disso? Tenho certeza de que você poderia ao menos adivinhar o que max_length=120 means. O legal é que eles significam exatamente a mesma coisa: limitar este campo a 120 caracteres ou menos.

Adição de dados ao banco de dados

Com Django:

BlogArticle.objects.create(
    title="Hello World",
    content="Coming Soon",
    slug="hello-world",
    publish_timestamp=None,
)

Com SQL:

INSERT INTO `articles_blog_article` (`user_id`, `title`, `slug`, `content`, `publish_timestamp`) 
VALUES (1, 'Hello World', 'hello-world', 'Coming Soon', NULL);

Quando se trata de simplicidade e clareza, eu acho que o vencedor acima é definitivamente Django e Python. title = "Hello World" é mais fácil do que descobrir o que está acontecendo com o valor equivalente da coluna (campo) em SQL. Não se engane, a forma como isto é escrito em SQL é muito eficaz quando se sabe o que se está fazendo.

Adicionando Múltiplas Linhas
com Django:

items = [
    BlogArticle(title='Hello Again 0', slug='hello-again-0', content="Coming Soon"),
    BlogArticle(title='Hello Again 1', slug='hello-again-1', content="Coming Soon"),
    BlogArticle(title='Hello Again 2', slug='hello-again-2', content="Coming Soon"),
    BlogArticle(title='Hello Again 3', slug='hello-again-3', content="Coming Soon"),
    BlogArticle(title='Hello Again 4', slug='hello-again-4', content="Coming Soon"),
]
BlogArticle.objects.bulk_create(items)

Com SQL:

INSERT INTO `articles_blog_article` (`user_id`, `title`, `slug`, `content`, `publish_timestamp`) 
VALUES (1, 'Hello Again 0', 'hello-again-0', 'Coming Soon', NULL),
    (1, 'Hello Again 1', 'hello-again-1', 'Coming Soon', NULL),
    (1, 'Hello Again 2', 'hello-again-2', 'Coming Soon', NULL),
    (1, 'Hello Again 3', 'hello-again-3', 'Coming Soon', NULL),
    (1, 'Hello Again 4', 'hello-again-4', 'Coming Soon', NULL);

Novamente, o código Python é mais legível, enquanto o código SQL dá mais informações sobre os dados reais. E, mais uma vez, Python está escrevendo este código SQL para nós usando o código Django acima. Bastante legal, não?

A razão pela qual eu mergulhei nesta comparação lado a lado não é para escolher, que é a melhor maneira de alavancar bancos de dados SQL, mas para destacar a capacidade de Pythonde ajudar a reduzir a sobrecarga de aprendizagem para escrever SQL bruto diretamente.

Há vários pacotes Python que eles essencialmente escrevem o SQL bruto para você, aqui estão alguns deles:

  • Django
  • Pandas
  • SQLAlchemy
  • Polars
  • Dask
  • Vaex
  • PythonMódulo CSV incorporado
  • Tartaruga ORM
  • Pônei ORM
  • SQLObject

Django Faz a Elevação Pesada
Os pacotes de mapeamento objeto-relacional (comumente chamados de ORMs) são o molho secreto de como Python pode alavancar bancos de dados SQL. Eu penso em um ORM como um intermediário que ajuda a mover dados em qualquer sintaxe nativa de qualquer linguagem de programação.

No início deste exercício, começamos a ver como isso se traduzia em Django, mas vamos agora expandir isso.

Supondo que temos dados em nosso banco de dados, podemos escrever um comando como este:

my_post = BlogArticle.objects.first()
Esta declaração irá consultar nosso banco de dados, extrair os dados, carregá-los em uma instância de um Python Classe, em seguida, atribuí-la à variável my_post.

A partir daqui, podemos agora fazer algo assim:

# using a django-managed python shell
# via python manage.py shell
>>> print(my_post.title)
Hello World

Neste caso, utilizamos a notação de pontos para acessar o title campo que foi declarado no BlogPost Modelo Django da seção anterior. Este campo corresponde a uma coluna em nossa tabela de banco de dados SQL articles_blog_article.

Graças à ORM, podemos fazer isso:

>>> my_post.title = "some other title"

Dentro deste exemplo de sessão shell Python , o my_post.title agora sempre ser "some other title". O banco de dados SQL subjacente, no entanto, ainda reconhece esses mesmos dados que Hello World. O banco de dados manterá os dados originais até que Python finalmente se comprometa (aka .save()) estes dados mudam para o banco de dados. Se Python nunca comprometer estes dados, eles nunca serão atualizados no banco de dados, o que faz parte da magia da ORM. Nós podemos uso e mudar os dados sem afetar os dados efetivamente armazenados. Quando queremos mudar o que está realmente acontecendo no banco de dados, executamos:

>>> my_post.title = "some other title again"
>>> my_post.save()

Após a execução .save() nosso banco de dados, para esta linha em particular, atualizará o título da coluna para corresponder exatamente ao que está escrito como uma string Python acima. Não esqueça que o .save() é especificamente para fazer compromissos com o banco de dados nos modelos Django. .save() não significa realmente nada para um Python Class sem herdar primeiro um formulário Django Model Class.

Construção com Django, MySQL, e Linode

Este é um dos muitos exemplos de como Django faz o trabalho pesado para você. Se você estiver interessado em uma abordagem moderna para implantar aplicações Django no Linode junto com um banco de dados MySQL gerenciado, GitHub Actions for CI/CD, Terraform e Ansible, confira o seguinte conteúdo agora disponível no Linode:

Para ajudar você a começar, o Código para Empresários GitHub tem um repositório de código que acompanha cada etapa da série. Boa sorte, e não deixe de me informar como as coisas estão indo através do Twitter @JustinMitchel.


Comentários

Deixe uma resposta

Seu endereço de e-mail não será publicado. Os campos obrigatórios estão marcados com *