Jak zapisać obrazek PIL w modelu, nie zapisując go wcześniej do pliku tymczasowego?
Słowem wstępu
Pisząc ostatnimi czasy portal z użyciem Django natknąłem się na parę problemów, które rozwiązać przyszło mi samemu, bo w internecie brak było gotowych recept. Takoż chciałbym jedno z takich rozwiązań umieścić tutaj, aby w przyszłości osoby mające podobny problem nie musiały się nad nim głowić, jak ja.
Zapisanie pliku przetwarzanego przez PIL w nowym obiekcie modelu, bez konieczności tworzenia plików tymczasowych
Czyli innymi słowy, jak wgrać na serwer plik, zmienić jego rozmiar, a następnie utworzyć obiekt reprezentujący go w galerii, tak aby nie trzeba było wpierw zapisywać oryginału na dysk, by Django nadało mu automatycznie jakąś nazwę pliku.
def generate_name(name, field, ext):
"""
Funkcja generująca nazwę dla pliku. Parametry:
name nazwa pliku w systemie użytkownika
field pole modelu do którego ma trafić obrazek
ext docelowe rozszerzenie pliku
"""
i = name.rfind('.')
if i>=0: name = name[:i]
name = field.field.generate_filename(field.field, name)
if not exists(MEDIA_ROOT + name + ext):
return name + ext
# Jeśli nazwa pliku jest zajęta, dołączamy do niej podkreślnik
# i próbujemy dołączać kolejne liczby, aż znajdziemy nazwę,
# która jest jeszcze wolna.
name += '_'
i = 0
while exists(MEDIA_ROOT + name + str(i) + ext):
i += 1
return name + str(i) + ext
# Otwieramy przesłany obrazek.
img = Image.open(form.cleaned_data.get("file"))
# Konwertujemy go na wszelki wypadek (gdyby u?żytkownik wysłał np. GIFa) na RGB.
img = img.convert("RGB")
# Jeśli jego rozmiar jest za duży — zmniejszamy go odpowiednio.
w, h = img.size
if w>800 or h>800 or (w>600 and h>600):
img.thumbnail((800, 600) if w>h else (600, 800), Image.ANTIALIAS)
# Tworzymy nowy obiekt klasy naszego modelu.
photo = Photo(author = request.user)
# Generujemy nazwę pliku,
filename = generate_name(form.cleaned_data.get("file").name, photo.file, '.jpg')
# zapisujemy obrazek…
img.save(MEDIA_ROOT + filename, "JPEG")
# …i wsadzamy do stworzonego wcześniej obiektu.
photo.file = filename
# // ewentualne ustawienie innych pól obiektu photo //
# A na koniec zapisujemy zapisujemy obiekt modelu w bazie danych.
photo.save