Switch to date-based URLs everywhere except the feed URLs of old posts, so I don't spam everyone's feedreader.
1.1 --- a/agdj/blog/feeds.py Sun Feb 01 01:10:45 2009 -0500
1.2 +++ b/agdj/blog/feeds.py Sun Feb 01 01:35:02 2009 -0500
1.3 @@ -12,7 +12,6 @@
1.4
1.5 """
1.6
1.7 -from django.core.urlresolvers import reverse
1.8 from django.http import HttpResponse, HttpResponseRedirect, Http404
1.9 from django.views.decorators.cache import cache_page
1.10
1.11 @@ -24,7 +23,7 @@
1.12
1.13 entry_kwargs = {}
1.14 entry_kwargs['title'] = entry.title
1.15 - entry_kwargs['guid'] = guid = reverse("view-blog-post", args=[entry.slug])
1.16 + entry_kwargs['guid'] = guid = entry.urls.feed_url
1.17 entry_kwargs['link'] = "http://adam.gomaa.us%s" % guid
1.18 entry_kwargs['description'] = entry.rendered
1.19 entry_kwargs['pubDate'] = entry.pub_date
1.20 @@ -37,7 +36,7 @@
1.21
1.22 item_kwargs = {}
1.23 item_kwargs['title'] = "Comment on %s" % comment.entry.title
1.24 - abs_url = reverse("view-blog-post", args=[comment.entry.slug])
1.25 + abs_url = comment.entry.feed_url
1.26 item_kwargs['link'] = "http://adam.gomaa.us%s" % abs_url
1.27 item_kwargs['guid'] = comment.entry.slug+str(comment.id)
1.28 item_kwargs['description'] = comment.rendered
2.1 --- a/agdj/blog/models.py Sun Feb 01 01:10:45 2009 -0500
2.2 +++ b/agdj/blog/models.py Sun Feb 01 01:35:02 2009 -0500
2.3 @@ -4,7 +4,7 @@
2.4 from tagging.fields import TagField
2.5
2.6 from agdj.blog.managers import PublicManager
2.7 -from agdj.utils import cached_property
2.8 +from agdj.utils import cached_property, dictproperty
2.9
2.10
2.11 class Entry(models.Model):
2.12 @@ -17,6 +17,17 @@
2.13 pub_date = models.DateTimeField(auto_now_add=True)
2.14 slug = models.CharField(max_length=64, unique=True)
2.15 public = models.BooleanField()
2.16 + SLUG_ONLY = "slug-only"
2.17 + DATE_BASED = "date-based"
2.18 + URL_SCHEME_CHOICES = (
2.19 + (SLUG_ONLY, "Slug Only"),
2.20 + (DATE_BASED, "Date-based"),
2.21 + )
2.22 + feed_url_scheme = models.CharField(
2.23 + max_length=64, choices=URL_SCHEME_CHOICES,
2.24 + help_text="Does this post use the new date-based URL or the old "
2.25 + "slug-based one in feed URLs and GUIDs?",
2.26 + default=DATE_BASED)
2.27
2.28 # This is a hack that even I don't understand
2.29 text_tags = TagField(db_column="tags")
2.30 @@ -45,6 +56,23 @@
2.31
2.32 return super(Entry, self).save(*args, **kwargs)
2.33
2.34 + @dictproperty
2.35 + def urls(self, name):
2.36 + from django.core.urlresolvers import reverse
2.37 +
2.38 + if name == "feed_url":
2.39 + if self.feed_url_scheme == self.DATE_BASED:
2.40 + return self.urls.view
2.41 + else:
2.42 + return reverse("redirect-to-date-url", args=[self.slug])
2.43 + elif name == "view":
2.44 + return reverse("view-blog-post",
2.45 + args=[self.pub_date.year,
2.46 + self.pub_date.strftime("%b").lower(),
2.47 + self.pub_date.day,
2.48 + self.slug])
2.49 +
2.50 +
2.51
2.52 @cached_property
2.53 def rendered(self):
3.1 --- a/agdj/blog/urls.py Sun Feb 01 01:10:45 2009 -0500
3.2 +++ b/agdj/blog/urls.py Sun Feb 01 01:35:02 2009 -0500
3.3 @@ -11,7 +11,10 @@
3.4 (r'^feed/$', feeds.latest),
3.5 (r'^feed/comments/$', feeds.comments),
3.6 (r'^feed/latest/$', redirect_to, {"url":"/blog/feed/"}),
3.7 - url(r'^(?P<slug>[-\w]+)/$', views.single_post, {}, "view-blog-post"),
3.8 + url(r'^(?P<slug>[-\w]+)/$', views.redirect_to_date_version, {}, "redirect-to-date-url"),
3.9 + url(r'^(?P<year>\d{4})/(?P<month>\w+)/(?P<day>\d+)/(?P<slug>[-\w]+)/$',
3.10 + views.single_post, {},
3.11 + "view-blog-post"),
3.12 )
3.13
3.14
4.1 --- a/agdj/blog/views.py Sun Feb 01 01:10:45 2009 -0500
4.2 +++ b/agdj/blog/views.py Sun Feb 01 01:35:02 2009 -0500
4.3 @@ -8,8 +8,14 @@
4.4 from agdj.utils import use_template
4.5
4.6
4.7 +def redirect_to_date_version(request, slug):
4.8 + "Redirect requests from the old URL scheme to the new one"
4.9 + post = get_object_or_404(models.Entry, slug=slug)
4.10 + return HttpResponseRedirect(post.urls.view)
4.11 +
4.12 +
4.13 @use_template("blog/single_post.html")
4.14 -def single_post(request, slug):
4.15 +def single_post(request, year, month, day, slug):
4.16 "Show a single post"
4.17
4.18 post = get_object_or_404(models.Entry, slug=slug)
5.1 --- a/agdj/core/templates/blog/post_list.html Sun Feb 01 01:10:45 2009 -0500
5.2 +++ b/agdj/core/templates/blog/post_list.html Sun Feb 01 01:35:02 2009 -0500
5.3 @@ -2,10 +2,8 @@
5.4 {% load cache %}
5.5
5.6 {% block content %}
5.7 -{% cache 500 all_posts %}
5.8 {% for object in posts %}
5.9 {% include "blog/render_post_summary.html" %}
5.10 {% endfor %}
5.11 -{% endcache %}
5.12 {% endblock %}
5.13
6.1 --- a/agdj/core/templates/blog/render_post_summary.html Sun Feb 01 01:10:45 2009 -0500
6.2 +++ b/agdj/core/templates/blog/render_post_summary.html Sun Feb 01 01:35:02 2009 -0500
6.3 @@ -1,8 +1,7 @@
6.4 {% load cache humanize microformats mkdn2 %}
6.5
6.6 -{% cache 500 post_summary object.slug %}
6.7 <div class="post-summary">
6.8 - <h3><a href="{% url agdj.blog.views.single_post object.slug %}">{{ object.title }}</a></h3>
6.9 + <h3><a href="{{ object.urls.view }}">{{ object.title }}</a></h3>
6.10 {% with object.public_comments as comments %}
6.11 <p>Posted <span class="humanize iso8601">{{ object.pub_date|iso8601 }}</span> - {% if comments %}
6.12 {{ comments|length|apnumber|capfirst }} comment{{ comments|pluralize }}
6.13 @@ -15,4 +14,3 @@
6.14 </div>
6.15 <div class="description">{{ object.description|markdown2 }}</div>
6.16 </div>
6.17 -{% endcache %}
7.1 --- a/agdj/core/templates/blog/single_post.html Sun Feb 01 01:10:45 2009 -0500
7.2 +++ b/agdj/core/templates/blog/single_post.html Sun Feb 01 01:35:02 2009 -0500
7.3 @@ -7,7 +7,7 @@
7.4 {% block header %}
7.5 <h1>
7.6 <a href="{% url agdj.blog.views.post_list %}">blog:</a>
7.7 - <a href="{% url agdj.blog.views.single_post post.slug %}">{{ post.title }}</a></h1>
7.8 + <a href="{{ post.urls.view }}">{{ post.title }}</a></h1>
7.9 {% endblock %}
7.10
7.11 {% block metadata %}
8.1 --- a/agdj/utils.py Sun Feb 01 01:10:45 2009 -0500
8.2 +++ b/agdj/utils.py Sun Feb 01 01:35:02 2009 -0500
8.3 @@ -56,3 +56,17 @@
8.4
8.5 return val
8.6 return property(_closure)
8.7 +
8.8 +
8.9 +def dictproperty(method):
8.10 + """Turn dictionary or attribute access into a function call"""
8.11 +
8.12 + class _Object(object):
8.13 + def __init__(self, obj):
8.14 + self.obj = obj
8.15 + def __getattr__(self, attr):
8.16 + return method(self.obj, attr)
8.17 + __getitem__ = __getattr__
8.18 + _Object.__name__ = method.__name__
8.19 +
8.20 + return property(_Object)