From 2b6691f8a5f683a45beaeb240e953aa38788cec2 Mon Sep 17 00:00:00 2001 From: Danielle McLean Date: Wed, 25 Oct 2017 12:31:08 +1100 Subject: [PATCH] Rudimentary but fully-functional entry permalink pages :3 --- Pipfile | 1 + Pipfile.lock | 80 +++++++++++-------- entries/kinds.py | 13 ++- entries/models.py | 16 ++++ entries/templates/entries/entry.html | 28 +------ entries/templates/entries/h-entry.html | 24 ++++++ entries/templates/entries/index.html | 2 +- entries/urls.py | 18 ++++- entries/views.py | 8 ++ lemoncurry/breadcrumbs.py | 2 +- lemoncurry/templates/lemoncurry/layout.html | 2 +- .../lemoncurry/tags/breadcrumbs.html | 8 +- lemoncurry/templatetags/lemoncurry_tags.py | 4 +- 13 files changed, 133 insertions(+), 73 deletions(-) create mode 100644 entries/templates/entries/h-entry.html diff --git a/Pipfile b/Pipfile index c952404..ddd12ec 100644 --- a/Pipfile +++ b/Pipfile @@ -20,6 +20,7 @@ django-activeurl = "*" django-otp = "*" qrcode = "*" django-otp-agents = "*" +python-slugify = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index d81ad7c..1f8c35f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1d582e5b51466de2e917f117b537193fd1826f51d3a9a218f83d392d68d0c461" + "sha256": "a6c119918001f41c9b233d8cf9606c9acd10c6dcc13ed248f88511b198d9e929" }, "host-environment-markers": { "implementation_name": "cpython", @@ -207,39 +207,39 @@ }, "psycopg2": { "hashes": [ - "sha256:3ab693b907b2c7a34c1dca198cfc454516cfd75440fd913bb372da6f70d6db55", - "sha256:3c99c88216e0fc62113a1177aae9db18a533274370e99a4537b433b87b319360", - "sha256:df70e0a387b0145a7a80de67d43d84e1c5a24a33bbfaedb96271876d573e5fb6", - "sha256:8d2003d23d8fc59f0f0a2e73c13baa41581006b8227a9d82bbdc1aa233285ba4", - "sha256:face605eea5826fa36600c04447b61674992bbd5eb177f66f86f61a04436dbd9", - "sha256:ebee4f59803eda1ed4035649469a713818dbf5b6de2e12396edd9fa228727c20", - "sha256:4d7c872d9c85745964cf8efabba3fb1a6010b345c18d0e2b620509f0444aa729", - "sha256:99a298b9030f8fd36f885c5d0661e4d5a059136a541bb6c4d7d1100e38da3cd1", - "sha256:b7646f7bdb42ba3cf7ef9f500f6514b5e413d25c5b3093d70e6ba52df417a83c", - "sha256:39369e40bc3e062da5da93ce5f1e7f9bed95e9a60cb6f003d316f2a834722e2d", - "sha256:c939b238cbc18e786909d20277c9f051241696ebb03ca9e3490094f526ce69a7", - "sha256:9a0a74a6f20d82c389095c88d4d281e66eb3ffbc09adf543dcec4bec22436569", - "sha256:16482d050db68503abbb693795d75e9fca287a00f662376759825404533ca87c", - "sha256:f74e50341f45fb9bcd3598c11b5774c3e4349ee38cf15c342cc7075c73ef1f95", - "sha256:e80a1ae04218e854a5d71085f9498c8c979033ca855cedeed3afc5d976c348ce", - "sha256:f07791ee5793621bfaaa844f731529cd72321280f94e8dc3bd4ef524d20f58f2", - "sha256:0bd0b1cf81eb6d74a77199570d5ce097fb3c6b8e57acc1edd328cef5c552f98a", - "sha256:4db0de7d6236acbf7d020926489b6c4b98e845ba98df11057f22d54866e26b20", - "sha256:604c49bf196c654c417ade1dc765bd23fe9bc3392d9a8c7184a7077142d621b3", - "sha256:6194e81d8839b636118f5275c53be3c70eb3c3abcf836de675c34b20c06025ea", - "sha256:e26aca5eb272869fdf8e55111f36026517c1c0799eb7ef1ddf67d4412affe1ef", - "sha256:35d1fec112337c2607c8ca17dee3c2f8455e07dd69d140ff8e86ef1240dace3d", - "sha256:891a70235c202158780fc0ab98d7ca2a7ed1625c26725b15119d47b2d852a5c6", - "sha256:4cca242df228364b4de6241c54553301856bc253d7f21e15009b11c812eb7b5c", - "sha256:3fbba0dd7f3ac458f355dcfc4d7d9cd082c19748e453bcd81bf9d8bc14260c01", - "sha256:04a5b2805c620ddecdff33e015631cc8d7ea8dd01e1fcc930bfe002fdc26b9e0", - "sha256:4fbe2c29f6d4c8d9eac5fc3c42c42036e7cc58e225036130b7713afa72489aac", - "sha256:471e3140e1cb241ecb53602cdc98fe305b82c854cfa53c3e343d642683dc96c7", - "sha256:279dbf220c94c9f73aefac719ea3b9550ca791389bc9184c15e835516bc8428d", - "sha256:a4d7134058e8869d785c0be386cd702fe2a4be14b678d7571a51045e1bbad862", - "sha256:9b7b16e26448b43cf167f785d8b5345007731ebf153a510e12dae826800caa65" + "sha256:594aa9a095de16614f703d759e10c018bdffeafce2921b8e80a0e8a0ebbc12e5", + "sha256:1cf5d84290c771eeecb734abe2c6c3120e9837eb12f99474141a862b9061ac51", + "sha256:0344b181e1aea37a58c218ccb0f0f771295de9aa25a625ed076e6996c6530f9e", + "sha256:25250867a4cd1510fb755ef9cb38da3065def999d8e92c44e49a39b9b76bc893", + "sha256:317612d5d0ca4a9f7e42afb2add69b10be360784d21ce4ecfbca19f1f5eadf43", + "sha256:9d6266348b15b4a48623bf4d3e50445d8e581da413644f365805b321703d0fac", + "sha256:ddca39cc55877653b5fcf59976d073e3d58c7c406ef54ae8e61ddf8782867182", + "sha256:988d2ec7560d42ef0ac34b3b97aad14c4f068792f00e1524fa1d3749fe4e4b64", + "sha256:7a9c6c62e6e05df5406e9b5235c31c376a22620ef26715a663cee57083b3c2ea", + "sha256:7a75565181e75ba0b9fb174b58172bf6ea9b4331631cfe7bafff03f3641f5d73", + "sha256:94e4128ba1ea56f02522fffac65520091a9de3f5c00da31539e085e13db4771b", + "sha256:92179bd68c2efe72924a99b6745a9172471931fc296f9bfdf9645b75eebd6344", + "sha256:b9358e203168fef7bfe9f430afaed3a2a624717a1d19c7afa7dfcbd76e3cd95c", + "sha256:009e0bc09a57dbef4b601cb8b46a2abad51f5274c8be4bba276ff2884cd4cc53", + "sha256:d3ac07240e2304181ffdb13c099840b5eb555efc7be9344503c0c03aa681de79", + "sha256:40fa5630cd7d237cd93c4d4b64b9e5ed9273d1cfce55241c7f9066f5db70629d", + "sha256:6c2f1a76a9ebd9ecf7825b9e20860139ca502c2bf1beabf6accf6c9e66a7e0c3", + "sha256:37f54452c7787dbdc0a634ca9773362b91709917f0b365ed14b831f03cbd34ba", + "sha256:8f5942a4daf1ffac42109dc4a72f786af4baa4fa702ede1d7c57b4b696c2e7d6", + "sha256:bf708455cd1e9fa96c05126e89a0c59b200d086c7df7bbafc7d9be769e4149a3", + "sha256:82c40ea3ac1555e0462803380609fbe8b26f52620f3d4f8eb480cfd8ceed8a14", + "sha256:207ba4f9125a0a4200691e82d5eee7ea1485708eabe99a07fc7f08696fae62f4", + "sha256:0cd4c848f0e9d805d531e44973c8f48962e20eb7fc0edac3db4f9dbf9ed5ab82", + "sha256:57baf63aeb2965ca4b52613ce78e968b6d2bde700c97f6a7e8c6c236b51ab83e", + "sha256:2954557393cfc9a5c11a5199c7a78cd9c0c793a047552d27b1636da50d013916", + "sha256:7c31dade89634807196a6b20ced831fbd5bec8a21c4e458ea950c9102c3aa96f", + "sha256:1286dd16d0e46d59fa54582725986704a7a3f3d9aca6c5902a7eceb10c60cb7e", + "sha256:697ff63bc5451e0b0db48ad205151123d25683b3754198be7ab5fcb44334e519", + "sha256:fc993c9331d91766d54757bbc70231e29d5ceb2d1ac08b1570feaa0c38ab9582", + "sha256:9d64fed2681552ed642e9c0cc831a9e95ab91de72b47d0cb68b5bf506ba88647", + "sha256:5c3213be557d0468f9df8fe2487eaf2990d9799202c5ff5cb8d394d09fad9b2a" ], - "version": "==2.7.3.1" + "version": "==2.7.3.2" }, "python-memcached": { "hashes": [ @@ -247,6 +247,13 @@ ], "version": "==1.58" }, + "python-slugify": { + "hashes": [ + "sha256:c3733135d3b184196fdb8844f6a74bbfb9cf6720d1dcce3254bdc434353f938f", + "sha256:57a385df7a1c6dbd15f7666eaff0ff29d3f60363b228b1197c5308ed3ba5f824" + ], + "version": "==1.2.4" + }, "pytz": { "hashes": [ "sha256:c883c2d6670042c7bc1688645cac73dd2b03193d1f7a6847b6154e96890be06d", @@ -293,6 +300,13 @@ "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9" ], "version": "==1.11.0" + }, + "unidecode": { + "hashes": [ + "sha256:61f807220eda0203a774a09f84b4304a3f93b5944110cc132af29ddb81366883", + "sha256:280a6ab88e1f2eb5af79edff450021a0d3f0448952847cd79677e55e58bad051" + ], + "version": "==0.4.21" } }, "develop": {} diff --git a/entries/kinds.py b/entries/kinds.py index fc61491..62f6ba1 100644 --- a/entries/kinds.py +++ b/entries/kinds.py @@ -1,13 +1,22 @@ -class Note: +class Entry: + fields = () + + @classmethod + def has(cls, field): + return field in cls.fields + + +class Note(Entry): id = 'note' icon = 'fa fa-paper-plane' plural = 'notes' -class Article: +class Article(Entry): id = 'article' icon = 'fa fa-file-text' plural = 'articles' + fields = ('slug', 'name') all = (Note, Article) diff --git a/entries/models.py b/entries/models.py index c2f8562..b3c349f 100644 --- a/entries/models.py +++ b/entries/models.py @@ -1,5 +1,7 @@ from django.contrib.auth import get_user_model from django.db import models +from django.urls import reverse +from slugify import slugify from . import kinds ENTRY_KINDS = [(k.id, k.__name__) for k in kinds.all] @@ -28,6 +30,20 @@ class Entry(models.Model): content=self.content ) + @property + def url(self): + kind = kinds.from_id[self.kind] + route = 'entries:{kind}_entry'.format(kind=kind.plural) + args = [self.id] + if kind.has('slug'): + route += '_slug' + args.append(self.slug) + return reverse(route, args=args) + + @property + def slug(self): + return slugify(self.name) + class Meta: verbose_name_plural = 'entries' ordering = ['-published'] diff --git a/entries/templates/entries/entry.html b/entries/templates/entries/entry.html index 395a41e..38a094a 100644 --- a/entries/templates/entries/entry.html +++ b/entries/templates/entries/entry.html @@ -1,24 +1,4 @@ -{% load humanize %}
-
- {% if entry.name %}

{{ entry.name }}

{% endif %} -
{{ entry.content }}
-
- -
+{% extends 'lemoncurry/layout.html' %} +{% block main %} +{% include 'entries/h-entry.html' %} +{% endblock %} diff --git a/entries/templates/entries/h-entry.html b/entries/templates/entries/h-entry.html new file mode 100644 index 0000000..395a41e --- /dev/null +++ b/entries/templates/entries/h-entry.html @@ -0,0 +1,24 @@ +{% load humanize %}
+
+ {% if entry.name %}

{{ entry.name }}

{% endif %} +
{{ entry.content }}
+
+ +
diff --git a/entries/templates/entries/index.html b/entries/templates/entries/index.html index 6dad30b..8ce5c44 100644 --- a/entries/templates/entries/index.html +++ b/entries/templates/entries/index.html @@ -4,7 +4,7 @@
    {% for entry in entries %}
  1. - {% include 'entries/entry.html' %} + {% include 'entries/h-entry.html' %}
  2. {% endfor %}
diff --git a/entries/urls.py b/entries/urls.py index c9fda2a..6cdc45c 100644 --- a/entries/urls.py +++ b/entries/urls.py @@ -6,7 +6,19 @@ app_name = 'entries' urlpatterns = [] for k in kinds.all: index = k.plural + '_index' - urlpatterns.extend(( - url(k.plural, views.index, name=index, kwargs={'kind': k}), - )) + urlpatterns.append( + url(r'^{k}$'.format(k=k.plural), views.index, name=index, kwargs={'kind': k}) + ) breadcrumbs.add(app_name + ':' + index, label=k.plural, parent='home:index') + + entry = k.plural + '_entry' + pattern = r'^{k}/(?P\d+)'.format(k=k.plural) + urlpatterns.append( + url(pattern + '$', views.entry, name=entry) + ) + breadcrumbs.add(app_name + ':' + entry, parent=app_name + ':' + index) + if k.has('slug'): + urlpatterns.append( + url(pattern + r'/(?P.+)$', views.entry, name=entry + '_slug') + ) + breadcrumbs.add(app_name + ':' + entry + '_slug', parent=app_name + ':' + index) diff --git a/entries/views.py b/entries/views.py index a9ca2e5..1f17bb2 100644 --- a/entries/views.py +++ b/entries/views.py @@ -8,3 +8,11 @@ def index(request, kind): 'entries': entries, 'title': kind.plural }) + + +def entry(request, id, slug=None): + entry = Entry.objects.get(pk=id) + return render(request, 'entries/entry.html', { + 'entry': entry, + 'title': entry.name or entry.content + }) diff --git a/lemoncurry/breadcrumbs.py b/lemoncurry/breadcrumbs.py index d71e6ba..1190a2b 100644 --- a/lemoncurry/breadcrumbs.py +++ b/lemoncurry/breadcrumbs.py @@ -1,7 +1,7 @@ breadcrumbs = {} -def add(route, label, parent=None): +def add(route, label=None, parent=None): breadcrumbs[route] = {'label': label, 'route': route, 'parent': parent} diff --git a/lemoncurry/templates/lemoncurry/layout.html b/lemoncurry/templates/lemoncurry/layout.html index adb8766..cd01ea5 100644 --- a/lemoncurry/templates/lemoncurry/layout.html +++ b/lemoncurry/templates/lemoncurry/layout.html @@ -35,7 +35,7 @@ {% if request.resolver_match.view_name %} - {% nav_crumbs request.resolver_match.view_name %} + {% nav_crumbs request.resolver_match.view_name title %} {% endif %} diff --git a/lemoncurry/templates/lemoncurry/tags/breadcrumbs.html b/lemoncurry/templates/lemoncurry/tags/breadcrumbs.html index 607bcc1..1fa0aea 100644 --- a/lemoncurry/templates/lemoncurry/tags/breadcrumbs.html +++ b/lemoncurry/templates/lemoncurry/tags/breadcrumbs.html @@ -2,13 +2,9 @@ {% endif %} diff --git a/lemoncurry/templatetags/lemoncurry_tags.py b/lemoncurry/templatetags/lemoncurry_tags.py index dbf63f7..37bc703 100644 --- a/lemoncurry/templatetags/lemoncurry_tags.py +++ b/lemoncurry/templatetags/lemoncurry_tags.py @@ -68,7 +68,7 @@ def nav_right(request): @register.inclusion_tag('lemoncurry/tags/breadcrumbs.html') -def nav_crumbs(route): +def nav_crumbs(route, title): crumbs = breadcrumbs.find(route) current = crumbs.pop() - return {'crumbs': crumbs, 'current': current} + return {'crumbs': crumbs, 'current': current, 'title': title}