Normalize article dates and update ArticlePage model to use DateTimeField; configure S3 storage settings and update requirements for django-storages

This commit is contained in:
Warren Chen 2025-11-10 14:58:22 +09:00
parent b04ad110a6
commit d75ea17b32
9 changed files with 65 additions and 10 deletions

View File

@ -0,0 +1,46 @@
# Generated by Django 5.2.7 on 2025-11-10 05:37
import datetime as dt
from django.conf import settings
from django.db import migrations, models
from django.utils import timezone
def normalize_article_dates(apps, schema_editor):
ArticlePage = apps.get_model("home", "ArticlePage")
for page in ArticlePage.objects.all():
if page.date is None:
continue
value = page.date
if isinstance(value, dt.datetime):
base = value
elif isinstance(value, dt.date):
base = dt.datetime.combine(value, dt.time.min)
else:
continue
if settings.USE_TZ and timezone.is_naive(base):
base = timezone.make_aware(base, timezone.get_default_timezone())
normalized = base.replace(hour=0, minute=0, second=0, microsecond=0)
if normalized != page.date:
ArticlePage.objects.filter(pk=page.pk).update(date=normalized)
class Migration(migrations.Migration):
dependencies = [
('home', '0012_rename_recommended_articlepage_trending_and_more'),
]
operations = [
migrations.AlterField(
model_name='articlepage',
name='date',
field=models.DateTimeField(verbose_name='Published date'),
),
migrations.RunPython(normalize_article_dates, migrations.RunPython.noop),
]

View File

@ -35,7 +35,7 @@ class CategoryMixin:
"title": category.title,
"items": ArticlePage.objects.child_of(category)
.live()
.order_by("-first_published_at")[:HORIZON_SIZE],
.order_by("-date")[:HORIZON_SIZE],
"url": category.url,
"layout": "horizon",
}
@ -45,7 +45,7 @@ class CategoryMixin:
paginator = Paginator(
ArticlePage.objects.child_of(self)
.live()
.order_by("-first_published_at"),
.order_by("-date"),
PAGE_SIZE,
)
page_number = request.GET.get("page") if request else None
@ -84,7 +84,7 @@ class CategoryMixin:
# No request means no pagination (e.g., homepage)
return {
"title": latest_page.title,
"items": ArticlePage.objects.live().order_by("-first_published_at")[
"items": ArticlePage.objects.live().order_by("-date")[
:BLOCK_SIZE
],
"url": latest_page.url,
@ -92,7 +92,7 @@ class CategoryMixin:
else:
# Paginated view
paginator = Paginator(
ArticlePage.objects.live().order_by("-first_published_at"), PAGE_SIZE
ArticlePage.objects.live().order_by("-date"), PAGE_SIZE
)
page_number = request.GET.get("page")
@ -111,7 +111,7 @@ class CategoryMixin:
def get_trending_articles(self, request=None, exclude_ids=None):
trending_page = TrendingPage.objects.first()
articles_qs = ArticlePage.objects.filter(trending=True).live().order_by(
"-first_published_at"
"-date"
)
# Exclude specified article IDs
@ -178,7 +178,7 @@ class HomePage(Page, CategoryMixin):
"url": category.url,
"items": ArticlePage.objects.descendant_of(category)
.live()
.order_by("-first_published_at")[:HORIZON_SIZE],
.order_by("-date")[:HORIZON_SIZE],
"layout": "horizon",
}
)
@ -256,7 +256,7 @@ class ArticlePage(Page):
related_name="+",
help_text="文章內文橫幅圖片",
)
date = models.DateField("Published date")
date = models.DateTimeField("Published date")
intro = models.CharField(max_length=250, blank=True)
body = StreamField(
[
@ -292,7 +292,7 @@ class ArticlePage(Page):
.exclude(id=self.id)
.filter(tags__id__in=tag_ids)
.distinct()
.order_by("-first_published_at")[:4]
.order_by("-date")[:4]
)
else:
related_articles = ArticlePage.objects.none()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

View File

@ -170,13 +170,21 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static")
STATIC_URL = "/static/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
MEDIA_URL = f'{os.environ.get("AWS_S3_ENDPOINT_URL")}/{os.environ.get("AWS_STORAGE_BUCKET_NAME")}/'
# Default storage settings
# See https://docs.djangoproject.com/en/5.2/ref/settings/#std-setting-STORAGES
STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
"BACKEND": "storages.backends.s3boto3.S3Boto3Storage",
"OPTIONS": {
"endpoint_url": os.environ.get("AWS_S3_ENDPOINT_URL"),
"access_key": os.environ.get("AWS_ACCESS_KEY_ID"),
"secret_key": os.environ.get("AWS_SECRET_ACCESS_KEY"),
"bucket_name": os.environ.get("AWS_STORAGE_BUCKET_NAME"),
"region_name": os.environ.get("AWS_S3_REGION_NAME", default="us-east-1"),
"addressing_style": "path",
},
},
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",

View File

@ -4,3 +4,4 @@ gunicorn
dj-database-url
psycopg[binary]
python-dotenv
django-storages[boto3]