Add attachments and resize images
This commit is contained in:
parent
74e93762ca
commit
9f6ffcb1a3
14 changed files with 140 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -273,3 +273,4 @@ dmypy.json
|
||||||
|
|
||||||
.idea
|
.idea
|
||||||
staticfiles/
|
staticfiles/
|
||||||
|
media/
|
||||||
|
|
0
attachments/__init__.py
Normal file
0
attachments/__init__.py
Normal file
10
attachments/admin.py
Normal file
10
attachments/admin.py
Normal file
|
@ -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"]
|
5
attachments/apps.py
Normal file
5
attachments/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AttachmentsConfig(AppConfig):
|
||||||
|
name = "attachments"
|
30
attachments/migrations/0001_initial.py
Normal file
30
attachments/migrations/0001_initial.py
Normal file
|
@ -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)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
18
attachments/migrations/0002_auto_20200826_1814.py
Normal file
18
attachments/migrations/0002_auto_20200826_1814.py
Normal file
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
22
attachments/migrations/0003_auto_20200826_1843.py
Normal file
22
attachments/migrations/0003_auto_20200826_1843.py
Normal file
|
@ -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=""),
|
||||||
|
),
|
||||||
|
]
|
0
attachments/migrations/__init__.py
Normal file
0
attachments/migrations/__init__.py
Normal file
38
attachments/models.py
Normal file
38
attachments/models.py
Normal file
|
@ -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)
|
3
attachments/tests.py
Normal file
3
attachments/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
3
attachments/views.py
Normal file
3
attachments/views.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
|
@ -68,6 +68,7 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
"articles",
|
"articles",
|
||||||
|
"attachments",
|
||||||
"anymail",
|
"anymail",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -164,6 +165,9 @@ else:
|
||||||
"django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
|
"django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MEDIA_URL = "/media/"
|
||||||
|
MEDIA_ROOT = BASE_DIR / "media"
|
||||||
|
|
||||||
AUTH_USER_MODEL = "articles.User"
|
AUTH_USER_MODEL = "articles.User"
|
||||||
|
|
||||||
BLOG = {
|
BLOG = {
|
||||||
|
|
|
@ -13,10 +13,12 @@ Including another URLconf
|
||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
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.contrib import admin
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from articles.views import feeds, html
|
from articles.views import feeds, html
|
||||||
|
from blog import settings
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
@ -29,3 +31,6 @@ urlpatterns = [
|
||||||
"<slug:slug>/comment/", html.ArticleDetailView.as_view(), name="create-comment"
|
"<slug:slug>/comment/", html.ArticleDetailView.as_view(), name="create-comment"
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
|
@ -3,3 +3,4 @@ markdown==3.2.2
|
||||||
gunicorn==20.0.4
|
gunicorn==20.0.4
|
||||||
Pygments==2.6.1
|
Pygments==2.6.1
|
||||||
django-anymail[mailgun]==7.2.1
|
django-anymail[mailgun]==7.2.1
|
||||||
|
pillow==7.2.0
|
||||||
|
|
Reference in a new issue