Implement pagination for news archive
authorMagnus Hagander <magnus@hagander.net>
Sat, 26 Sep 2020 13:13:55 +0000 (15:13 +0200)
committerMagnus Hagander <magnus@hagander.net>
Sat, 26 Sep 2020 13:13:55 +0000 (15:13 +0200)
For now we do 10 items per page, but that's easy to adjust.

Paginate based on the date (so create an index on the date field to
simplify this), making page rendering and load a *lot* faster.

pgweb/news/migrations/0007_news_date_idx.py [new file with mode: 0644]
pgweb/news/models.py
pgweb/news/views.py
pgweb/urls.py
templates/news/newsarchive.html

diff --git a/pgweb/news/migrations/0007_news_date_idx.py b/pgweb/news/migrations/0007_news_date_idx.py
new file mode 100644 (file)
index 0000000..53fc651
--- /dev/null
@@ -0,0 +1,19 @@
+# Generated by Django 2.2.11 on 2020-09-26 13:11
+
+import datetime
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('news', '0006_sending_email'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='newsarticle',
+            name='date',
+            field=models.DateField(db_index=True, default=datetime.date.today),
+        ),
+    ]
index d4920ef5599b7252ded00ceec03035953cb21d98..3b2948d9e5b2852bbe6308340f5635d7f247f460 100644 (file)
@@ -27,7 +27,7 @@ class NewsTag(models.Model):
 class NewsArticle(TwoModeratorsMixin, TristateModerateModel):
     org = models.ForeignKey(Organisation, null=False, blank=False, verbose_name="Organisation", help_text="If no organisations are listed, please check the <a href=\"/account/orglist/\">organisation list</a> and contact the organisation manager or <a href=\"mailto:webmaster@postgresql.org\">webmaster@postgresql.org</a> if none are listed.", on_delete=models.CASCADE)
     email = models.ForeignKey(OrganisationEmail, null=True, blank=True, verbose_name="Reply email", help_text="Pick a confirmed email associated with the organisation. This will be used as the reply address of posted news.", on_delete=models.CASCADE)
-    date = models.DateField(null=False, blank=False, default=date.today)
+    date = models.DateField(null=False, blank=False, default=date.today, db_index=True)
     title = models.CharField(max_length=200, null=False, blank=False)
     content = models.TextField(null=False, blank=False)
     tweeted = models.BooleanField(null=False, blank=False, default=False)
index d06a8779f88cfa9d3eb448d3dd63bc5af48557f5..b09cadb13ef89452b146c4d1539a589a97ab5fec 100644 (file)
@@ -7,18 +7,33 @@ from pgweb.util.moderation import ModerationState
 
 from .models import NewsArticle, NewsTag
 
+import datetime
 import json
 
+# Number of items per page in the news archive
+NEWS_ITEMS_PER_PAGE = 10
 
-def archive(request, tag=None, paging=None):
-    if tag:
+
+def archive(request, tag=None, paginator=None):
+    if tag and tag.strip('/'):
         tag = get_object_or_404(NewsTag, urlname=tag.strip('/'))
         news = NewsArticle.objects.select_related('org').filter(modstate=ModerationState.APPROVED, tags=tag)
     else:
         tag = None
         news = NewsArticle.objects.select_related('org').filter(modstate=ModerationState.APPROVED)
+    if paginator and paginator.strip('/'):
+        news = news.filter(date__lte=datetime.datetime.strptime(paginator.strip('/'), '%Y%m%d'))
+
+    allnews = list(news.order_by('-date')[:NEWS_ITEMS_PER_PAGE + 1])
+    if len(allnews) == NEWS_ITEMS_PER_PAGE + 1:
+        # 11 means we have a second page, so set a paginator link
+        paginator = allnews[9].date.strftime("%Y%m%d")
+    else:
+        paginator = None
+
     return render_pgweb(request, 'about', 'news/newsarchive.html', {
-        'news': news,
+        'news': allnews[:NEWS_ITEMS_PER_PAGE],
+        'paginator': paginator,
         'tag': tag,
         'newstags': NewsTag.objects.all(),
     })
index 2c5d754ce8c1d85981e72520cc0580de59a43174..a65dc2310e4e24af0af4dcee07b1cd1b3cbff5cd 100644 (file)
@@ -33,7 +33,7 @@ urlpatterns = [
     url(r'^dyncss/(?P<css>base).css$', pgweb.core.views.dynamic_css),
 
     url(r'^about/$', pgweb.core.views.about),
-    url(r'^about/newsarchive/([^/]+/)?$', pgweb.news.views.archive),
+    url(r'^about/newsarchive/(?P<tag>[^/]*/)?(?P<paginator>[0-9]{8}/)?$', pgweb.news.views.archive),
     url(r'^about/news/(?P<itemid>\d+)(?P<slug>-.*)?/$', pgweb.news.views.item),
     url(r'^about/news/(?P<slug>[^/]+)-(?P<itemid>\d+)/$', pgweb.news.views.item),
     url(r'^about/news/taglist.json/$', pgweb.news.views.taglist_json),
index 2324e3abdf84d34edb7362e6217619d96004d607..d38c73016d3c6e2053f5b8725e9d986457b8264c 100644 (file)
@@ -2,7 +2,7 @@
 {%load markup%}
 {%block title%}News Archive{%if tag%} - {{tag.name}}{%endif%}{%endblock%}
 {%block contents%}
-<h1>News Archive{%if tag%} - {{tag.name}}{%endif%} <i class="far fa-newspaper"></i></h1>
+<h1><a href="/about/newsarchive/">News Archive</a>{%if tag%} - {{tag.name}}{%endif%} <i class="far fa-newspaper"></i></h1>
 
 <p>
 {%for t in newstags%}<span class="newstag"><a class="btn btn-primary" href="/about/newsarchive/{{t.urlname}}/">{{t.name}}</a></span> {%endfor%}
 {{obj.content|markdown:"safe"|striptags|truncatewords:20}}
 <p><a href="/about/news/{{obj.title|slugify}}-{{obj.id}}/">Read more...</a></p>
 {%endfor%}
-<p><a href="/account/news/new/">Submit news</a></p>
+
+{%if paginator%}
+<a class="btn btn-primary" href="/about/newsarchive/{{tag.urlname|default:""}}/{{paginator}}/">Older news...</a>
+{%endif%}
+
+<p>
+  News articles are either from the PostgreSQL project or contributeed by other related organisations. If you with to share news
+  related to PostgreSQL, you may <a href="/account/news/new/">submit</a> your own articles for consideration after logging in.
+</p>
 {%endblock%}