Django Rest Framework'e büyük dosya yükleme
DRF görünüm setine PUT ile büyük bir dosya (4GB) yüklemeye çalışıyorum.
Yükleme sırasında hafızam sabit. % 100'de, python çalıştırma sunucusu işlemi gittikçe daha fazla RAM alır ve çekirdek tarafından öldürülür. Bunun putyönteminde bir günlük satırım var APIViewancak işlem bu yöntem çağrısından önce öldürüldü.
Bu ayarı dosya kullanımını zorlamak için kullanıyorum FILE_UPLOAD_HANDLERS = ["django.core.files.uploadhandler.TemporaryFileUploadHandler"]
Bu hafıza zirvesi nereden geliyor? Sanırım dosya içeriğini belleğe yüklemeye çalışıyor ama neden (ve nerede)?
Daha fazla bilgi:
- Doğru ve yanlış hata ayıklamayı denedim
- Çalıştırma sunucusu, bir traefik'in arkasındaki bir pencerede, ancak traefik AFAIK'te herhangi bir sınırlama yoktur ve yükleme% 100'e ulaşır.
daphneRunserver yerine aynı davranışı alır mıyım henüz bilmiyorum- DÜZENLEME: ön kullanım a
Content-Type multipart/form-data - DÜZENLEME: Denedim
FileUploadParserve(FormParser, MultiPartParser)ayrıştırıcı sınıflarım içinAPIView
Yanıtlar
TL; DR:
Ne DRF ne de Django sorunu, 2,5 yıldır bilinen bir Daphne sorunu . Çözüm, şu an için uvicorn, hypercorn veya başka bir şey kullanmaktır.
Açıklamalar
Burada gördüğünüz şey Django Rest Framework'ten şu şekilde gelmiyor:
- FileUploadParser, dosya yığınlarını parçalar halinde okurken , büyük dosya yüklemelerini işlemek içindir ;
- Görünümünüzün yürütülmemesi ,request.FILES özelliğe erişene kadar yürütülmeyen ayrıştırıcıları ortadan kaldırır
Daphne'den bahsettiğiniz gerçeği, bana benzer bir sorundan bahseden ve Daphne'nin tüm gövdeyi RAM'e yüklemeden önce tüm gövdeyi RAM'e yüklerken büyük dosya yüklemelerini işlemediği bir koda işaret eden bu SO yanıtını hatırlatıyor . (Kod, yazım sırasında ana şubesinde hala mevcuttur)
Aynı davranışı görüyorsunuz runserverçünkü yüklendiğinde, Daphne geliştirici amaçları için WebSockets desteği sağlamak için ilk çalıştırma sunucusu komutunu kendisiyle değiştirir.
Bunun gerçek suçlu olduğundan emin olmak için, Kanalları devre dışı bırakmayı / varsayılan Django çalıştırma sunucusunu çalıştırmayı deneyin ve uygulamanızın OOM Killer tarafından öldürülüp öldürülmediğini kendiniz görün.
Django rest ile çalışıp çalışmadığını bilmiyorum, ancak dosyayı parçalamayı deneyebilirsiniz.
[...]
anexo_files = request.FILES.getlist('anexo_file_'+str(k))
index = 0
for file in anexo_files:
index = index + 1
extension = os.path.splitext(str(file))[1]
nome_arquivo_anexo = 'media/uploads/' + os.path.splitext(str(file))[0] + "_" + str(index) + datetime.datetime.now().strftime("%m%d%Y%H%M%S") + extension
handle_uploaded_file(file, nome_arquivo_anexo)
AnexoProjeto.objects.create(
projeto=projeto,
arquivo_anexo = nome_arquivo_anexo
)
[...]
Handle_uploaded_file nerede
def handle_uploaded_file(f, nome_arquivo):
with open(nome_arquivo, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)