Django File Upload Geniş Özet

2 minute read

Manuel File Upload

Veritabaninda herhangi bir ilgili alana kayit yapmadan sadece dosya upload etmenin nasil oldugunu gosterme amaciyla bu kismi ekliyorum. Tabii buradaki ornek kod, araya veritabani islemleri eklenerek kullanila da bilir fakat modellerle iliskili dosya yukleme islemleri icin bir sonraki baslikta anlatilanlar daha kullanislidir.

from django.shortcuts import render
from django.conf import settings
from django.core.files.storage import FileSystemStorage

def simple_upload(request):
    if request.method == 'POST' and request.FILES['myfile']:
        myfile = request.FILES['myfile']
        fs = FileSystemStorage()
        filename = fs.save(myfile.name, myfile)
        uploaded_file_url = fs.url(filename)
        return render(request, 'core/simple_upload.html', {
            'uploaded_file_url': uploaded_file_url
        })
    return render(request, 'core/simple_upload.html')

File Upload With ModelForm

https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/#handling-uploaded-files-with-a-model

Dosyanin validasyonunu ve kaydini FileSystemStorage() sinifini kullanmadan ModelForm’lar araciligiyla da yapabiliriz. Peki nasil?

models.py

from django.core.exceptions import ValidationError
import datetime
import os
import uuid

def content_file_name(instance, filename):
    _datetime = datetime.datetime.now()
    datetime_str = _datetime.strftime("%Y-%m-%d_%H-%M-%S")
    ext = filename.split('.')[-1]
    filename = "%s_%s.%s" % (datetime_str, uuid.uuid4(), ext)
    return os.path.join('uploads/', filename)

def file_size(value):
    limit = 2 * 1024 * 1024
    if value.size > limit:
        raise ValidationError('File too large. Size should not exceed 2 MiB.')

class MyModel(models.Model):
    meta_data = models.CharField(max_length=500)
    document = models.FileField(upload_to=content_file_name, blank=True, null=True, validators=[
        file_size, FileExtensionValidator(allowed_extensions=['pdf', 'png', 'jpeg', 'jpg'])])        

views.py

@api_view(['POST'])
@csrf_exempt
def upload_document(request):
    try:
        if request.method == 'POST' and request.FILES['document']:
            form = ProposalForm(request.POST, request.FILES)
            if form.is_valid():
                instance = form.save()
                return Response({'status': 'ok'}, status=201)
            else:
                print(form.errors)
            return Response(status=status.HTTP_400_BAD_REQUEST)
    except KeyError:
        return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

forms.py

from django.forms import ModelForm, ModelChoiceField, widgets
from django import forms
from .models import *


class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        exclude = ()

REQUEST

Postman Request Example

Yukaridaki yapi, ornek olarak verdigimiz istekten gelen dosyayi kaydedecek ve modeldeki alanlara karsilik gelen verileri veritabanina yazacaktir.

Burada sayan-i dikkat olan bir kac hususa dikkat cekmek istiyorum,

Goruldugu uzere , document isimli FileField tipindeki alanimiza validators ve upload_to isimli iki parametre gecilmis. validators icerisinde yuklenen dosyanin uzantisi ve boyutu olmak uzere 2 farkli validasyon yapiliyor. Eger yuklenmek istenen dosya bunlardan birisine uymazsa form.is_valid() ifadesi false donuyor yani dosyamiz upload olmuyor ve veritabani kaydi da yapilmiyor.

upload_to ifadesine karsilik gelen content_file_name fonksiyonu ise dosyaya benzersiz (unique) bir isim vermek icin kullandigim bir fonksiyon.

Bu parametereler zorunlu degil fakat ModelForm ile upload yaparken bu parametreleri kullanmak bana cok kullanisli geliyor.

Bir diger deginmek istedigim husus if request.method == ‘POST’ and request.FILES[‘document’]: satirinda gordugumuz request.FILES[‘document’] ifadesi. Burada parantez icerisindeki document ifadesi , istegi atarken dosyaya verdigimiz anahtar (key). Form validasyonunun yapilabilmesi icin bu anahtar ifadenin modelimizdeki dosyayi ifade alanla ayni ismi sahip olmasi gerekli. Yani modelimizdeki FileField ;

bir_mini_dosya = models.FileField(…)

seklinde tanimli ise, istekte dosyaya karsilik gelen anahtar da bir_mini_dosya olmali.

Kaynaklar

https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/

https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html

https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/#handling-uploaded-files-with-a-model

Leave a comment