Avançar para o conteúdo principal
BlogBases 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 ligadas a uma base de dados altamente escalonável. Estou aqui para vos falar sobre a redução do atrito diário que vem com a construção e apoio a aplicações modernas utilizando SQL e Python para abstrair a complexidade e tornar os nossos trabalhos e vidas um pouco mais fáceis.

Sem entrar nas ervas daninhas, podemos assumir:

  • SQL está optimizado para bases de dados SQL
  • Python não está optimizado para bases de dados SQL

Este exercício suporta directamente o ebook Understanding Databases e a minha nova série educativa Linode LIVE! usando Python e ferramentas Pythonic para executar comandos em SQL em bruto sem a necessidade de escrever SQL de facto. Estou a usar a modelação de dados de Django, mas a sintaxe é muito semelhante 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 numa aplicação Django chamada Articles (As aplicações Django são essencialmente componentes que constituem a totalidade de um projecto Django).

Agora temos dois nomes para trabalhar:

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

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

articles_blog_article

Django faz esta magia por nós.

Se estivéssemos a utilizar a concha 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 vejamos as colunas do 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)

Para além de escrever uma configuração básica, Django fez todo o trabalho SQL para nós nesta base de dados MySQL. Neste momento, Django não fez nada de muito impressionante. De facto, a maior parte deste exercício não foi concebido para destacar Django ou Python como um substituto de SQL, mas para lembrar o facto de que as abstracções funcionam.

A Ascensão de Python e o Custo do Atrito

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

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

Creio que estas generalizações tendem a ser verdadeiras devido à sintaxe inglesa de fazer as coisas 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 exactamente os mesmos dados. A declaração Python , contudo, devolve uma lista de Python objectos (items) que quase qualquer desenvolvedor Python com uma vasta experiência pode utilizar. Os resultados em bruto do SQL teriam de ser convertidos antes de serem utilizados numa aplicação Python .

Descrições de campo
Se olharmos mais de perto para 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 fricção?
  • Qual deles é mais fácil de compreender o que se passa?

O que fornece apenas informação suficiente?

Se não fosse um programador e serrasse varchar(120)o que pensaria disso? Tenho quase a certeza de que conseguiria pelo menos adivinhar o que max_length=120 means. O mais fixe é que significam exactamente a mesma coisa: limitar este campo a 120 caracteres ou menos.

Acrescentar dados à base 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, penso que o vencedor acima é definitivamente Django e Python. title = "Hello World" é mais fácil do que descobrir o que está a acontecer com o valor equivalente da coluna (campo) em SQL. Não se enganem, a forma como isto é escrito em SQL é muito eficaz quando se sabe o que se está a fazer.

Adição de Várias 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);

Mais uma vez, o código Python é mais legível enquanto que o código SQL dá mais informações sobre os dados reais. E, mais uma vez, Python está a escrever este código SQL para nós utilizando o código Django acima. Bastante limpo, huh?

A razão pela qual mergulhei nesta comparação lado a lado não é para escolher, que é a melhor maneira de aproveitar as bases de dados SQL, mas para destacar a capacidade de Pythonde ajudar a reduzir a sobrecarga de aprendizagem para escrever SQL em bruto directamente.

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

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

Django Faz o Levantamento Pesado
Os pacotes de mapeamento objeto-relacional (geralmente referidos como ORMs) são o molho secreto de como Python pode aproveitar as bases de dados SQL. Penso num ORM como um intermediário que ajuda a mover os dados na sintaxe nativa de qualquer linguagem de programação.

No início deste exercício, começámos a ver como isto se traduzia para Django, mas vamos agora expandir isto.

Assumindo que temos dados na nossa base de dados, podemos escrever um comando como este:

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

A partir daqui, podemos agora fazer algo como isto:

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

Neste caso, utilizámos a notação de pontos para aceder ao title campo que foi declarado no BlogPost Modelo Django da secção anterior. Este campo corresponde a uma coluna na nossa tabela da base de dados SQL articles_blog_article.

Graças à ORM, podemos fazer isto:

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

Dentro deste exemplo de sessão de shell Python , o my_post.title irá agora sempre ser "some other title". A base de dados SQL subjacente, no entanto, ainda reconhece estes mesmos dados que Hello World. A base de dados manterá os dados originais até que Python finalmente se comprometa (aka .save()) estes dados mudam para a base de dados. Se Python nunca submeter estes dados, eles nunca serão actualizados na base de dados, o que faz parte da magia do ORM. Nós podemos utilização e alteração os dados sem afectar os dados efectivamente armazenados. Quando queremos alterar o que está realmente a acontecer na base de dados, corremos:

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

Depois de correr .save() a nossa base de dados, para esta linha em particular, actualizará o título da coluna para corresponder exactamente ao que está escrito como uma string Python acima. Não se esqueça que a .save() é especificamente para fazer compromissos com a base de dados em 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 si. Se estiver interessado numa abordagem moderna de implantação de aplicações Django em Linode juntamente com uma base de dados MySQL gerida, GitHub Actions for CI/CD, Terraform, e Ansible, consulte o seguinte conteúdo agora disponível em Linode:

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

Comentários

Deixe uma resposta

O seu endereço de correio electrónico não será publicado. Os campos obrigatórios estão marcados com *