Visão geral
Neste guia, você pode aprender como modelar relacionamentos entre coleções no Django MongoDB Backend. Como o MongoDB é um banco de dados de documento , o Django MongoDB Backend fornece campos de modelo incorporados que armazenam dados relacionados em um único documento em vez de várias coleções. O Django MongoDB Backend também fornece um campo de array , que permite armazenar uma lista de valores escalares relacionados no documento pai .
Este guia explica quando usar cada abordagem e fornece exemplos para demonstrar as estratégias.
Dados de amostra
Os exemplos nesta guia definem modelos que representam as seguintes coleções no banco de dados do sample_mflix :
movies: armazena informações sobre filmesembedded_movies: Estendemoviescom incorporações de gráficos vetoriaisusers: Armazena informações sobre os visualizadores de filmescomments: armazena informações sobre comentários do filme
Para saber mais sobre o sample_mflix banco de dados, consulte Amostra de conjunto de dados Mflix na documentação do MongoDB Atlas .
Estratégias de desnormalização
Bancos de dados relacionais normalizam dados em tabelas separadas e usam junções para combinar dados relacionados no momento da query. O modelo de documento do MongoDB permite que você incorpore dados relacionados diretamente dentro de um documento pai, o que é chamado de desnormalização. O Django MongoDB Backend suporta ambas as abordagens, mas recomendamos que você desnormalize seus dados para melhor desempenho.
Para desnormalizar, escolha uma das seguintes estratégias:
Incorporarmodelos relacionados: armazene dados relacionados dentro do documento pai usando um
EmbeddedModelFieldEmbeddedModelArrayFieldou. Os dados incorporados são armazenados no mesmo documento MongoDB que o pai e recuperados em uma única operação de leitura.Armazenar dados de array: armazene uma lista de valores escalares relacionados diretamente no documento pai usando
ArrayFieldum. Os dados de array são recuperados em uma única operação de leitura sem$lookupoperações.
Incorporar modelos relacionados
Use um modelo incorporado quando todas as seguintes condições se aplicarem:
Os dados relacionados são sempre lidos junto com o documento principal.
Os dados relacionados pertencem a um único principal e não são compartilhados em vários documentos.
O número de itens relacionados é limitado e previsível.
Para incorporar dados relacionados, defina uma classe de modelo incorporado como uma subclasse de EmbeddedModel e, em seguida, use um EmbeddedModelField para armazená-los no modelo principal.
O exemplo a seguir define um modelo embarcado Director e, em seguida, define um modelo Movie que armazena uma instância do modelo Director:
from django.db import models from django_mongodb_backend.models import EmbeddedModel from django_mongodb_backend.fields import EmbeddedModelField class Director(EmbeddedModel): first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) class Movie(models.Model): title = models.CharField(max_length=200) director = EmbeddedModelField(Director, null=True, blank=True)
Para saber mais sobre modelos embarcados, consulte Armazenar dados de modelo embarcados no guia Criar modelos.
Armazenar dados de array
Use um ArrayField para armazenar uma lista de valores escalares relacionados diretamente no documento principal. Os dados da matriz são armazenados no mesmo documento MongoDB e recuperados em uma única operação de leitura sem executar $lookup operações. Use essa estratégia quando as seguintes condições se aplicarem:
Os valores relacionados são escalares simples, como strings ou inteiros.
O tamanho da array é limitado e previsível.
O exemplo seguinte define um modelo Movie que armazena uma lista de strings no campo cast :
from django.db import models from django_mongodb_backend.fields import ArrayField class Movie(models.Model): title = models.CharField(max_length=200) cast = ArrayField(models.CharField(max_length=100), blank=True)
Para armazenar arrays de documentos estruturados em vez de valores escalares, use um EmbeddedModelArrayField. Para saber mais, consulte Armazenar dados de array de modelos incorporados no guia Criar modelos.
Campos relacionais
Importante
As queries em campos relacionais usam o operador do MongoDB,$lookup que pode ser lento para coleções grandes. Quando possível, use modelos embarcados. Para saber mais sobre considerações de desempenho, consulte Limitações de desempenho.
Se seus dados estiverem estruturados de forma semelhante a um banco de dados relacional e você precisar modelar grandes conjuntos de dados hierárquicos, poderá usar os seguintes campos relacionais do Django que vinculam documentos em collections separadas:
Importante
Você não pode usar campos relacionais dentro de classes de modelo incorporadas ou como base_field de um ArrayField.
Chave estrangeira
Use um campo para criar um relacionamento de muitos para um entre dois modelos. Cada documento no modelo de referência vincula a um documento no modelo referenciado. Passe os seguintes argumentos para ForeignKey o ForeignKey() construtor:
to: a classe de modelo à qual vincularon_delete: O comportamento de exclusão quando você exclui o documento referenciado
O exemplo seguinte vincula um modelo Comment a um modelo Movie usando um campo ForeignKey . Quando você exclui um documento sample_mflix.movies, todos os documentos sample_mflix.comments relacionados também são excluídos:
from django.db import models class Movie(models.Model): title = models.CharField(max_length=200) class Comment(models.Model): movie = models.ForeignKey( Movie, on_delete=models.CASCADE, ) text = models.TextField()
Dica
Para saber mais sobre as on_delete opções do, consulte foreignKey.on_delete na documentação do Django.
OneToOneField
Use um campo para criar um relacionamento um-para-um entre dois modelos. Cada documento no modelo de referência vincula a exatamente um documento no modelo referenciado. Passe os seguintes argumentos para OneToOneField o OneToOneField() construtor:
to: a classe de modelo à qual vincularon_delete: O comportamento de exclusão quando o documento referenciado é excluído
O exemplo seguinte define um modelo EmbeddedMovie que se vincula a um modelo Movie usando um campo OneToOneField . Quando você exclui um documento sample_mflix.movies, o documento sample_mflix.embedded_movies vinculado também é excluído:
from django.db import models from django_mongodb_backend.fields import ArrayField class Movie(models.Model): title = models.CharField(max_length=200) class EmbeddedMovie(models.Model): movie = models.OneToOneField( Movie, on_delete=models.CASCADE, ) plot_embedding = ArrayField(models.FloatField(), blank=True)
Campos manytomany
Use um campo para criar um relacionamento de muitos para muitos entre dois modelos. Cada documento em qualquer modelo pode ser vinculado a vários documentos no outro modelo. Passe a classe do modelo a ser vinculada como o primeiro argumento para ManyToManyField o ManyToManyField() construtor.
O exemplo seguinte vincula um modelo Viewer a um modelo Movie. Cada visualizador pode assistir a vários filmes, e cada filme pode ser assistido por vários visualizadores:
from django.db import models class Movie(models.Model): title = models.CharField(max_length=200) class Viewer(models.Model): name = models.CharField(max_length=100) email = models.CharField(max_length=200) watched = models.ManyToManyField(Movie, blank=True)
Converter dados relacionais em dados incorporados
Se você tiver modelos existentes que usam campos relacionais e desejam melhorar o desempenho de leitura, poderá convertê-los para usar modelos incorporados. Isso elimina $lookup operações e armazena todos os dados relacionados em um único documento do MongoDB .
Este exemplo define um modelo Movie que tem os seguintes campos relacionais:
ForeignKey, que se vincula aDirectorOneToOneField, que se vincula aAwardManyToManyField, que se vincula aWriter
from django.db import models class Director(models.Model): first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) class Award(models.Model): wins = models.IntegerField(default=0) nominations = models.IntegerField(default=0) text = models.CharField(max_length=100) class Writer(models.Model): first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) class Movie(models.Model): title = models.CharField(max_length=200) director = models.ForeignKey( Director, null=True, on_delete=models.SET_NULL, ) awards = models.OneToOneField( Award, null=True, on_delete=models.SET_NULL, ) writers = models.ManyToManyField(Writer, blank=True)
Para converter esses campos relacionais em campos incorporados, altere cada modelo relacionado para estender EmbeddedModel em vez de models.Model e, em seguida, substitua os campos relacionais do modelo Movie pelos campos incorporados correspondentes:
Substitua o
ForeignKeypor umEmbeddedModelFieldSubstitua o
OneToOneFieldpor umEmbeddedModelFieldSubstitua o
ManyToManyFieldpor umEmbeddedModelArrayField
O exemplo seguinte mostra o modelo Movie convertido:
from django.db import models from django_mongodb_backend.models import EmbeddedModel from django_mongodb_backend.fields import ( EmbeddedModelField, EmbeddedModelArrayField, ) class Director(EmbeddedModel): first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) class Award(EmbeddedModel): wins = models.IntegerField(default=0) nominations = models.IntegerField(default=0) class Writer(EmbeddedModel): first_name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) class Movie(models.Model): title = models.CharField(max_length=200) director = EmbeddedModelField(Director, null=True, blank=True) awards = EmbeddedModelField(Award, null=True, blank=True) writers = EmbeddedModelArrayField(Writer, blank=True)
Informações adicionais
Para saber como executar query de dados em modelos relacionados, consulte Queries de campo avançadas no guia Especificar uma query.
Para saber mais sobre os campos relacionais do Django, consulte a referência de campo do Modelo na documentação do Django.
Para saber mais sobre modelos incorporados, consulte Armazenar dados de modelo incorporado no guia Criar modelos.