DEV Community

Eduardo Oliveira
Eduardo Oliveira

Posted on

django-storages + S3: lidando com arquivos de mesmo nome

O django é um framework para desenvolvimento web na linguagem Python e seu funcionamento é, majoritariamente, baseado em alguns padrões de design, como, por exemplo, os decorators e adapters. O sistema de storage de arquivos de mídia e de arquivos estáticos funciona, de modo simples, seguindo o padrão adapter.

Arquivos de Mídia são os arquivos enviados pelos usuários por meio dos campos de upload de arquivo (ImageField e FileField).

Arquivos Estáticos são os arquivos para serem usados nos layouts (como, por exemplo, scripts, styles e assets).

O django-storages é uma biblioteca que fornece alguns adapters para o sistema de armazenamento do django, enviando arquivos para provedores de nuvem, como a AWS (Amazon Web Service) e a GCP (Google Cloud Platform).


O problema

Utilizando o sistema original de armazenamento, em disco, do django para arquivos estáticos e para arquivos de mídia ao mesmo tempo existem alguns comportamentos que são padrão e que acabam passando sem serem notados:

Durante o upload de arquivos (FileField ou ImageField) quando enviamos dois arquivos com o mesmo nome, por padrão, o adapter de storage adiciona uma parte aleatória no fim do nome do arquivo, permitindo, dessa forma, o upload de ambos sem conflitarem.

Já os arquivos estáticos, aqueles que são "coletados" utilizando o comando python manage.py collectstatic, os conflitos de nomes são resolvidos de uma forma diferente: "o arquivo que for localizado primeiro em uma das localizações especificadas será utilizado" (Ver Referência [1]).

Essa diferença entre os comportamentos, configurações padrões para ambos os adapters, é de suma importância pois, não faz sentido adicionar um jquery_xyz.js, por exemplo, a cada vez que o comando python manage.py collectstatic for executado.

django-storages e a unificação do comportamento

O django-storages, mais especificamente seus adapters S3Boto3Storage e S3StaticStorage, unifica esses dois comportamentos em uma configuração AWS_S3_FILE_OVERWRITE que por padrão é True e de acordo com [2], "por padrão, arquivos com o mesmo nome serão sobrescritos um ao outro. Mude para False para adicionar caracteres extra adicionados".

O problema ainda persiste, pois o comportamento precisa ser diferente para cada um dos adapter. A solução é não alterar a propriedade AWS_S3_FILE_OVERWRITE e sobrescrever o adapter de upload de arquivos de mídia definindo essa configuração localmente:

# core/storages.py
from storages.backends.s3boto3 import S3Boto3Storage

class MediaS3Boto3Storage(S3Boto3Storage):
    file_overwrite = False
Enter fullscreen mode Exit fullscreen mode

Assim, alterando no settings.py a configuração principal:

DEFAULT_FILE_STORAGE = 'core.storages.MediaS3Boto3Storage'
Enter fullscreen mode Exit fullscreen mode

No exemplo, abaixo, o mesmo arquivo foi enviado duas vezes para o bucket S3 e o segundo aparece já com os caracteres acrescentados ao fim do nome:

Exemplo do Bucket


Observações

Segundo o comentário em [3], não existe a necessidade em, de fato, substituir o adapter e a configuração AWS_S3_FILE_OVERWRITE = False poderia ser utilizada devido ao fato de que o django remove o arquivo antes de criar o novo ao executar o comando python manage.py collectstatic, porém essa é uma questão não confirmada e que, além disso, deixa preocupações, por exemplo, em futuras atualizações do próprio django.


Referências

[1] The staticfiles app - Django Documentation.

[2] Amazon S3 - Django-storages Documentation.

[3] jschneier on GitHub.

Top comments (0)