Artigo original: How to use Django with MongoDB by adding just one line of code.

Escrito por: Siddy Zen

Para usar o MongoDB como banco de dados de back-end em seu projeto em Django, basta adicionar esta única linha em seu arquivo settings.py:

DATABASES = {'default': {      'ENGINE': 'djongo',      'NAME': 'nome-do-banco',   }}

É muito simples!

A seguir, faça login no home admin (localhost:8000/admin/) e comece a adicionar "embedded documents" (documentos incorporados, em português) no MongoDB usando a interface gráfica de administrador:

1_ZkPNUvkWB5VoMn6bEoKxPA

Em outubro de 2017, o MongoDB concluiu a última fase para se tornar uma companhia de capital aberto, abrindo seu IPO com um preço inicial de $24 e conseguindo $192 milhões no processo. O capital da empresa vem crescendo desde então.

O MongoDB oferece um software de banco de dados de código aberto. Ele é muito útil para start-ups que estão buscando iniciar nos negócios apesar do pouco orçamento inicial disponível. Uma análise no Google Trends das pesquisas pelo termo MongoDB revelam um aumento constante na busca do termo.

1_76GlEAQiLFt4eGsFaiJIIw
Google Trends — Termo pesquisado: MongoDB

O MongoDB tem se tornado um banco de dados cada vez mais popular. Bancos de dados e sistemas de gerenciamento de bancos de dados (SGBDs) existem há mais de cinco décadas. Surgiram no início dos anos 1960 e a opção mais popular foi o banco de dados relacional.

Porém, o MongoDB vem se intitulando como um sistema de banco de dados "não-relacional" e tem feito uma grande propaganda sobre essa abordagem de armazenamento de dados que utiliza. Então, o que exatamente é importante aqui?

MongoDB x SQL

Praticamente todos os sistemas de bancos de dados relacionais utilizam a Linguagem de Consulta Estruturada (SQL), ou uma versão otimizada dela, para se comunicar com o software de gerenciamento de dados. Muitos cursos universitários são dedicados exclusivamente à compreensão e domínio da sintaxe do SQL.

O SQL tornou-se a linguagem padrão para o trabalho com qualquer software de banco de dados, seja ele proprietário ou de código aberto. Então, surgiu o MongoDB e decidiu demonstrar um completo desrespeito a essa linguagem ancestral de poder, criando sua própria sintaxe de consulta.

A língua é a de Mordor, a qual não vou pronunciar aqui., mas isto em língua comum quer dizer, aproximadamente: "Um anel para todos governar, um anel para encontrá-los, um anel para todos trazer e na escuridão aprisioná-los." – Gandalf (de O Senhor dos Anéis)

MongoDB sem esquemas x esquemas do SQL: em um banco de dados em SQL, é impossível adicionar dados enquanto você não definir tabelas e tipos de campos no que é chamado de esquema (em inglês, schema). Em um banco de dados do MongoDB, os dados podem ser adicionados em qualquer lugar, a qualquer momento. Não há necessidade de especificar com antecedência um documento de design ou mesmo uma coleção de documentos.

Documentos do MongoDB  x tabelas do SQL: bancos de dados em SQL fornecem uma coleção de tabelas de dados relacionados. Cada linha é um registro diferente. O design é rígido: não podemos usar a mesma tabela para armazenar informações diferentes ou inserir uma string onde um número é esperado.

O banco de dados do MongoDB armazena apenas documentos de pares campo-valor, semelhantes ao formato JSON. Documentos similares podem ser armazenados em uma coleção de documentos, que é análoga a uma tabela do SQL. Entretanto, você pode armazenar qualquer tipo de dado em um documento — o MongoDB não vai reclamar. As tabelas em SQL implementam um modelo de dados rígido, o que torna mais difícil que erros sejam cometidos. O MongoDB é mais flexível e permissivo, mas a possibilidade de armazenar qualquer tipo de dado em qualquer lugar pode levar a erros de consistência.

Existe uma infinidade de conteúdo na internet argumentando que o MongoDB não é um superconjunto do SQL. Softwares que rodam em SQL não podem ser migrados para MongoDB. Vou me arriscar aqui afirmando que, no contexto do Django, MongoDB é um superconjunto do SQL.

Então, por que essa crença popular de que MongoDB não é um superconjunto do SQL existe, para começo de conversa?

O MongoDB requer desnormalização de dados: o MongoDb não oferece suporte a JOIN. Isso significa que vamos precisar desnormalizar nossos documentos. Documentos desnormalizados implicam maior velocidade nas consultas, mas atualizar informações nos campos do documento, em múltiplos documentos desnormalizados, é significativamente mais lento.

Não existem JOINs: consultas do SQL oferecem uma poderosa cláusula JOIN. Podemos obter dados relacionados em várias tabelas usando uma única instrução SQL. Em bancos de dados não relacionais como o MongoDB, não existem JOINs. Isso que dizer que você precisa executar muitas consultas e depois fazer a união dos dados manualmente em seu código.

Sem transações: em bancos de dados SQL, duas ou mais atualizações podem ser executadas em uma transação – um invólucro que segue o princípio do "tudo ou nada", que garante sucesso ou falha das operações. Se executarmos duas atualizações individualmente, uma pode ter sucesso e a outra pode falhar – deixando nossos dados fora de sincronia. Colocar as mesmas atualizações em uma transação garante que ambas tenham sucesso ou ambas falhem.

Sem restrições de chave estrangeira: a maioria dos bancos de dados de SQL permite que você assegure a integridade dos dados usando restrições de chave estrangeira. Isso garante que todas as linhas tenham uma chave estrangeira válida no código que corresponde a uma entrada na tabela de join, e garante que um registro da tabela de join não seja removido caso uma ou mais linhas ainda possuam referência a ele.

O esquema impõe essas regras ao banco de dados. É impossível que desenvolvedores e usuários adicionem, editem, ou removam registros, o que poderia resultar em dados inválidos ou registros órfãos. As mesmas opções para integridade de dados não estão disponíveis no MongoDB. Você pode armazenar o que quiser, independentemente de quaisquer outros documentos. Idealmente, um único documento serviria como a única fonte de informação sobre um item.

A necessidade de um modelo de banco de dados

Objetos são a abstração de dados que Python usa. Todos os dados em um programa em Python são representados por objetos ou pelas relações que eles têm entre si. Embora objetos sejam uma boa maneira de representar dados, um problema surge quando queremos tornar os dados persistentes. A quantidade de dados pode ser enorme, e precisa ser recuperada da memória persistente de maneira rápida e eficiente. Logo, será necessário usar um software de banco de dados para armazenar esses objetos. Um possível software de banco de dados é um que seja relacional, baseado em SQL.

Um mapeador objeto-relacional (ORM) é uma biblioteca de código que automatiza a transferência de dados armazenados em tabelas de banco de dados relacionais em objetos Python que são usados no código Python. ORMs fornecem uma abstração em alto nível de um banco de dados relacional, o que permite que um desenvolvedor digite código Python em vez de sintaxe SQL para criar, ler, atualizar e excluir dados e esquemas de seu banco de dados. Desenvolvedores podem usar linguagem de programação Python, com a qual estão familiarizados, ao invés de escrever declarações em SQL ou procedimentos armazenados.

Um exemplo de framework ORM para Python é o SQLAlchemy. Esse ORM possui um método de associar classes definidas pelo usuário em Python a tabelas de banco de dados, e instâncias dessas classes (objetos) a linhas em suas respectivas tabelas. Ele também possui um sistema que, de modo transparente, sincroniza todas as alterações de estado entre objetos e linhas que estão a eles relacionadas. Frameworks para a web, como o Flask, usam o SQLAlchemy para armazenar dados de maneira persistente.

Django ORM: o Django vem com seu próprio ORM, ou modelo, para ser mais específico . O modelo é a única fonte definitiva de informações sobre seus dados. Ele contém os campos e comportamentos essenciais dos dados que você está armazenando. Geralmente, cada modelo mapeia para uma única tabela de banco de dados. O modelo também torna possível alternar entre vários bancos de dados relacionais, como Oracle SQL, MySQL ou MSSQL.

Usando o ORM do Django para adicionar documentos ao MongoDB

Digamos que você deseja criar uma plataforma de blogs usando Django e MongoDB como back-end.

No arquivo app/models.py do blog, defina o modelo BlogContent:

from djongo import modelsfrom djongo.models import forms
class BlogContent(models.Model):    comment = models.CharField(max_length=100)    author = models.CharField(max_length=100)    class Meta:        abstract = True

Para acessar o modelo usando o Django Admin, você precisa de uma definição de formulário para o modelo acima. Defina desta maneira:

class BlogContentForm(forms.ModelForm):    class Meta:        model = BlogContent        fields = (            'comment', 'author'        )

Agora, incorpore seu BlogContent dentro de um BlogPost usando o EmbeddedModelField, assim:

class BlogPost(models.Model):    h1 = models.CharField(max_length=100)    content = models.EmbeddedModelField(        model_container=BlogContent,        model_form=BlogContentForm    )   

Pronto! Rode o Django Admin em localhost:8000/admin/ e essa tela vai aparecer:

1_ZkPNUvkWB5VoMn6bEoKxPA--1-

Depois, assuma que você quer "estender" o campo author para conter mais informações além do nome. Suponhamos que você precise tanto do nome quanto do e-mail. Basta tornar o campo author em um campo "embedded" ao invés de  "char":

class Author(models.Model):    name = models.CharField(max_length=100)    email = models.CharField(max_length=100)    class Meta:        abstract = Trueclass AuthorForm(forms.ModelForm):    class Meta:        model = Author        fields = (            'name', 'email'        )
class BlogContent(models.Model):    comment = models.CharField(max_length=100)    author = models.EmbeddedModelField(        model_container=Author,        model_form=AuthorForm    )    class Meta:        abstract = True

Se um post de blog tiver conteúdo diverso de vários autores, defina um novo modelo:

class MultipleBlogPosts(models.Model):    h1 = models.CharField(max_length=100)    content = models.ArrayModelField(        model_container=BlogContent,        model_form=BlogContentForm    )

Rode o Django Admin com as atualizações. Agora você tem:

1_9ckp5M7dit8F_U9A78FrMA

Formas de integrar Django ao MongoDB

O ORM do Django consiste em várias camadas de abstração empilhadas uma em cima da outra.

1_l41TRyQAGHD5lg0LHXzzag
Diagrama do Django ORM

Como desenvolvedor para a web, você pode encarar o desafio de conectar o Django ao MongoDB de duas maneiras. Dê uma olhada na stack do framework Django acima para tentar adivinhar possíveis pontos de conexão.

Use um modelo compatível com o MongoDB

1_dGgjMqDl6dzrVHJZdiPbfw
Mudança de um modelo Django para um ODM

Você pode evitar completamente o uso de modelos Django "com tudo incluso" em seu projeto. Em vez disso, use um framework de terceiros como MongoEngine ou Ming em seus projetos do Django.

Tenha em mente, porém, que escolher um modelo diferente significa perder:

Você então diminuiria a expertise nos modelos existentes do Django e aumentaria no novo framework de modelos. Talvez a maior desvantagem, no entanto, resida no fato de que seu projeto não vai poder usar nenhum dos pacotes do django.contrib! Esqueça o uso de Admin, Sessions, Users, Auth e outros módulos desse pacote em seu projeto.

Algumas dessas desvantagens são compensadas quando bifurcamos uma nova ramificação no próprio Django. O Django-nonrel, por exemplo, é uma ramificação independente que adiciona ao Django suporte a banco de dados NoSQL. Ele permite que aplicações do Django portáteis sejam escritas. Entretanto, a interface admin não funciona completamente. Além disso, não existe uma comunidade ativa de fato desenvolvendo o projeto.

Django MongoDB Engine é outro back-end com MongoDB para Django, que é uma bifurcação do MongoEngine ODM.

Djongo – transpilador de Django SQL para MongoDB

1_QpOq4GaUl_wX4_F6JYkQTA
Djongo — O transpilador de SQL para MongoDB

Outra abordagem é traduzir a sintaxe da consulta SQL gerada pelo ORM do Django em comandos do pymongo. O Djongo é um desses compiladores de consultas SQL para MongoDB. Ele traduz toda string de consulta SQL em um documento de consulta do mongoDB. O resultado é que todos os modelos do Django e modelos relacionados funcionam assim. Por conta disso, temos as seguintes vantagens:

  • Reuso dos modelos Django: o Django é um framework estável em contínuo desenvolvimento e aprimoramento. O ORM do Django é um tanto quanto extenso e dotado de vários recursos . Definir um ORM de terceiros para trabalhar com o MongoDB significa reproduzir todo o ORM do Django novamente. O novo ORM precisa se alinhar constantemente com o ORM do Django. Diversas funcionalidades do Django nunca vão ser incluídas em um ORM de terceiros. A ideia com o Djongo é reutilizar recursos existentes do ORM do Django, traduzindo então consultas SQL para a sintaxe do MongoDB.
  • A sintaxe do SQL nunca vai mudar: independentemente de futuras adições no Django, com o Djongo, seu projeto não vai ter problemas no futuro!

Fazendo o Django funcionar com o MongoDB

Emulando o esquema no MongoDB: embora não haja suporte a esquemas no MongoDB, isso pode ser emulado. O Djongo fornece o suporte a esquemas necessário no Django, usando e definindo uma combinação de regras de validação do MongoDB e criando uma coleção __schema__. A coleção __schema__ armazena informações para suportar recursos como a chave SQL AUTOINCREMENT.

Suporte a JOIN no MongoDB: na versão 3.2, o MongoDB introduziu o operador $lookup. Ele realiza um left outer join com uma coleção no mesmo banco de dados para filtrar documentos da coleção "unida" (em inglês, joined) para processamento. A etapa de $lookup faz uma correspondência de igualdade entre um campo dos documentos de entrada e um campo dos documentos da coleção "unida".

Para cada documento de entrada, a fase de $lookup adiciona um campo array cujos elementos são os documentos correspondentes da coleção "unida". A fase de $lookup passa, então,  esses documentos remodelados para a próxima etapa.

O Djongo usa o operador de agregação $lookup para realizar todas as consultas de JOIN relacionadas ao Django. É assim que ele faz o módulo admin e os outros módulos contrib funcionarem.

Suporte a transações no MongoDB: apesar do poder das operações atômicas de um único documento, existem casos onde transações multidocumento são necessárias. Ao se executar uma transação composta por operações sequenciais, certos problemas surgem, como nos casos em que, se operação falhar, a operação anterior dentro da transação precisa voltar a seu estado anterior — ou seja,  "tudo ou nada".

Para situações que exigem transações multidocumento, o Djongo implementa o padrão de confirmação de duas fases (documentação em inglês), fornecendo suporte para essas atualizações multidocumento. O uso de confirmação de duas fases garante a consistência dos dados e, em caso de erro , o estado que precedeu a transação pode ser recuperado.

O Djongo surgiu com seu próprio conjunto de preceitos, na verdade. Então, quais são as desvantagens de se optar pelo uso do Djongo em seu projeto Django?

Desempenho: o ORM do Django faz o trabalho pesado de converter manipulações complexas de objeto em strings de consulta no padrão SQL. Se o banco de dados do seu back-end fosse baseado em SQL, você poderia passar essa string de consulta diretamente para ele sem quase nenhum pós-processamento. Usando Djongo, entretanto, a string de consulta precisará ser convertida em um documento de consulta do MongoDB.

Isso vai exigir alguns ciclos de CPU. Porém, se ciclos adicionais de CPU são realmente um problema, você não deveria estar usando Python em primeiro lugar.

Conclusão

Apresentei diversas maneiras de se integrar Django ao MongoDB. Você encontrará uma infinidade de literatura on-line descrevendo a MongoEngine e outras variantes para fazer isso.

Concentrei-me no Djongo, que é um novo conector que torna isso possível de uma maneira diferente, é fácil de usar e simplifica o processo de migração de um back-end com SQL para o MongoDB, adicionando apenas uma linha de código.