From 9f6ffcb1a3f3a82a95fe7df26aa28f7c70cae026 Mon Sep 17 00:00:00 2001 From: Gabriel Augendre Date: Wed, 26 Aug 2020 19:04:48 +0200 Subject: [PATCH] Add attachments and resize images --- .gitignore | 1 + attachments/__init__.py | 0 attachments/admin.py | 10 +++++ attachments/apps.py | 5 +++ attachments/migrations/0001_initial.py | 30 +++++++++++++++ .../migrations/0002_auto_20200826_1814.py | 18 +++++++++ .../migrations/0003_auto_20200826_1843.py | 22 +++++++++++ attachments/migrations/__init__.py | 0 attachments/models.py | 38 +++++++++++++++++++ attachments/tests.py | 3 ++ attachments/views.py | 3 ++ blog/settings.py | 4 ++ blog/urls.py | 5 +++ requirements.txt | 1 + 14 files changed, 140 insertions(+) create mode 100644 attachments/__init__.py create mode 100644 attachments/admin.py create mode 100644 attachments/apps.py create mode 100644 attachments/migrations/0001_initial.py create mode 100644 attachments/migrations/0002_auto_20200826_1814.py create mode 100644 attachments/migrations/0003_auto_20200826_1843.py create mode 100644 attachments/migrations/__init__.py create mode 100644 attachments/models.py create mode 100644 attachments/tests.py create mode 100644 attachments/views.py diff --git a/.gitignore b/.gitignore index b7b79d2..a5f8d9c 100644 --- a/.gitignore +++ b/.gitignore @@ -273,3 +273,4 @@ dmypy.json .idea staticfiles/ +media/ diff --git a/attachments/__init__.py b/attachments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/attachments/admin.py b/attachments/admin.py new file mode 100644 index 0000000..859f088 --- /dev/null +++ b/attachments/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin +from django.contrib.admin import register + +from attachments.models import Attachment + + +@register(Attachment) +class AttachmentAdmin(admin.ModelAdmin): + list_display = ["description", "original_file", "processed_file"] + list_display_links = ["description"] diff --git a/attachments/apps.py b/attachments/apps.py new file mode 100644 index 0000000..9571434 --- /dev/null +++ b/attachments/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AttachmentsConfig(AppConfig): + name = "attachments" diff --git a/attachments/migrations/0001_initial.py b/attachments/migrations/0001_initial.py new file mode 100644 index 0000000..4134823 --- /dev/null +++ b/attachments/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 3.1 on 2020-08-26 16:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Attachment", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("description", models.CharField(blank=True, max_length=500)), + ("file", models.FileField(upload_to="")), + ("processed", models.BooleanField(blank=True, default=False)), + ], + ), + ] diff --git a/attachments/migrations/0002_auto_20200826_1814.py b/attachments/migrations/0002_auto_20200826_1814.py new file mode 100644 index 0000000..d0a09fa --- /dev/null +++ b/attachments/migrations/0002_auto_20200826_1814.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1 on 2020-08-26 16:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("attachments", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="attachment", + name="description", + field=models.CharField(max_length=500), + ), + ] diff --git a/attachments/migrations/0003_auto_20200826_1843.py b/attachments/migrations/0003_auto_20200826_1843.py new file mode 100644 index 0000000..dfe08ed --- /dev/null +++ b/attachments/migrations/0003_auto_20200826_1843.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1 on 2020-08-26 16:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("attachments", "0002_auto_20200826_1814"), + ] + + operations = [ + migrations.RenameField( + model_name="attachment", old_name="file", new_name="original_file", + ), + migrations.RemoveField(model_name="attachment", name="processed",), + migrations.AddField( + model_name="attachment", + name="processed_file", + field=models.FileField(blank=True, null=True, upload_to=""), + ), + ] diff --git a/attachments/migrations/__init__.py b/attachments/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/attachments/models.py b/attachments/models.py new file mode 100644 index 0000000..d17987f --- /dev/null +++ b/attachments/models.py @@ -0,0 +1,38 @@ +import tempfile +from pathlib import Path + +from django.core.files import File +from django.db import models +from PIL import Image + + +class Attachment(models.Model): + description = models.CharField(max_length=500) + original_file = models.FileField() + processed_file = models.FileField(blank=True, null=True) + + def save(self, *args, **kwargs): + if self.processed_file: + return super().save(*args, **kwargs) + + try: + image = Image.open(self.original_file.path) + except IOError: + return self.save(*args, **kwargs) + max_width = 640 + if image.width > max_width: + ratio = image.height / image.width + height = round(max_width * ratio) + output = image.resize((max_width, height)) + else: + output = image.copy() + current_path = Path(image.filename) + temp_dir = Path(tempfile.mkdtemp()) + temp_path = temp_dir / (current_path.stem + "-resized" + current_path.suffix) + output.save(temp_path) + with open(temp_path, "rb") as output_file: + f = File(output_file) + self.processed_file.save(temp_path.name, f, save=False) + temp_path.unlink() + temp_dir.rmdir() + return super().save(*args, **kwargs) diff --git a/attachments/tests.py b/attachments/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/attachments/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/attachments/views.py b/attachments/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/attachments/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/blog/settings.py b/blog/settings.py index 22bbc96..b30f6e4 100644 --- a/blog/settings.py +++ b/blog/settings.py @@ -68,6 +68,7 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", "articles", + "attachments", "anymail", ] @@ -164,6 +165,9 @@ else: "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" ) +MEDIA_URL = "/media/" +MEDIA_ROOT = BASE_DIR / "media" + AUTH_USER_MODEL = "articles.User" BLOG = { diff --git a/blog/urls.py b/blog/urls.py index e5a76e3..82c6aff 100644 --- a/blog/urls.py +++ b/blog/urls.py @@ -13,10 +13,12 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from django.conf.urls.static import static from django.contrib import admin from django.urls import path from articles.views import feeds, html +from blog import settings urlpatterns = [ path("admin/", admin.site.urls), @@ -29,3 +31,6 @@ urlpatterns = [ "/comment/", html.ArticleDetailView.as_view(), name="create-comment" ), ] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/requirements.txt b/requirements.txt index 52b64f8..22ff154 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ markdown==3.2.2 gunicorn==20.0.4 Pygments==2.6.1 django-anymail[mailgun]==7.2.1 +pillow==7.2.0