diff options
-rw-r--r-- | feeds.py | 14 | ||||
-rw-r--r-- | news/migrations/0007_add_guid.py | 65 | ||||
-rw-r--r-- | news/migrations/0008_set_prior_guids.py | 83 | ||||
-rw-r--r-- | news/models.py | 24 | ||||
-rw-r--r-- | templates/feeds/news_description.html | 2 | ||||
-rw-r--r-- | templates/feeds/news_title.html | 2 | ||||
-rw-r--r-- | templates/feeds/packages_description.html | 2 | ||||
-rw-r--r-- | templates/feeds/packages_title.html | 2 |
8 files changed, 186 insertions, 8 deletions
@@ -1,6 +1,7 @@ import datetime from decimal import Decimal, ROUND_HALF_DOWN +from django.contrib.sites.models import Site from django.contrib.syndication.views import Feed from django.core.cache import cache from django.db.models import Q @@ -97,9 +98,18 @@ class PackageFeed(Feed): s += '.' return s + subtitle = description + def items(self, obj): return obj['qs'] + def item_guid(self, item): + # http://diveintomark.org/archives/2004/05/28/howto-atom-id + date = item.last_update + return 'tag:%s,%s:%s%s' % (Site.objects.get_current().domain, + date.strftime('%Y-%m-%d'), item.get_absolute_url(), + date.strftime('%Y%m%d%H%M')) + def item_pubdate(self, item): return item.last_update @@ -135,6 +145,7 @@ class NewsFeed(Feed): title = 'Arch Linux: Recent news updates' link = '/news/' description = 'The latest and greatest news from the Arch Linux distribution.' + subtitle = description title_template = 'feeds/news_title.html' description_template = 'feeds/news_description.html' @@ -146,6 +157,9 @@ class NewsFeed(Feed): return News.objects.select_related('author').order_by( '-postdate', '-id')[:10] + def item_guid(self, item): + return item.guid + def item_pubdate(self, item): return item.postdate diff --git a/news/migrations/0007_add_guid.py b/news/migrations/0007_add_guid.py new file mode 100644 index 0000000..5fa8193 --- /dev/null +++ b/news/migrations/0007_add_guid.py @@ -0,0 +1,65 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.add_column('news', 'guid', self.gf('django.db.models.fields.CharField')(default='', max_length=255), keep_default=False) + + def backwards(self, orm): + db.delete_column('news', 'guid') + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'news.news': { + 'Meta': {'ordering': "['-postdate']", 'object_name': 'News', 'db_table': "'news'"}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'guid': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'postdate': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + } + } + + complete_apps = ['news'] diff --git a/news/migrations/0008_set_prior_guids.py b/news/migrations/0008_set_prior_guids.py new file mode 100644 index 0000000..704b11c --- /dev/null +++ b/news/migrations/0008_set_prior_guids.py @@ -0,0 +1,83 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.conf import settings +from django.db import models + +class Migration(DataMigration): + '''The point of this migration is to not mark every news item as 'new' in + people's feed readers, and store the GUID perminantly with the news item. + All previously published news items will get their former auto-assigned + GUID; new ones will get a generated tag: URI and this won't apply to + them.''' + + def forwards(self, orm): + all_news = orm.News.objects.all().defer('content') + site = orm['sites.site'].objects.get(pk=settings.SITE_ID).domain + for news in all_news: + new_guid = 'http://%s/news/%s/' % (site, news.slug) + # looks totally silly, but prevents full updates of all fields, + # including content and last_modified which we want to leave alone + orm.News.objects.filter(pk=news.pk).update(guid=new_guid) + + def backwards(self, orm): + pass + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'news.news': { + 'Meta': {'ordering': "['-postdate']", 'object_name': 'News', 'db_table': "'news'"}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'news_author'", 'to': "orm['auth.User']"}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'guid': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'postdate': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + } + } + + complete_apps = ['sites', 'news'] diff --git a/news/models.py b/news/models.py index c2d644b..c4fb136 100644 --- a/news/models.py +++ b/news/models.py @@ -1,13 +1,16 @@ +from datetime import datetime + from django.db import models from django.contrib.auth.models import User +from django.contrib.sites.models import Site class News(models.Model): slug = models.SlugField(max_length=255, unique=True) author = models.ForeignKey(User, related_name='news_author') - postdate = models.DateTimeField("post date", auto_now_add=True, db_index=True) - last_modified = models.DateTimeField(editable=False, - auto_now=True, db_index=True) + postdate = models.DateTimeField("post date", db_index=True) + last_modified = models.DateTimeField(editable=False, db_index=True) title = models.CharField(max_length=255) + guid = models.CharField(max_length=255, editable=False) content = models.TextField() def get_absolute_url(self): @@ -22,10 +25,23 @@ class News(models.Model): get_latest_by = 'postdate' ordering = ['-postdate'] +def set_news_fields(sender, **kwargs): + news = kwargs['instance'] + now = datetime.now() + news.last_modified = now + if not news.postdate: + news.postdate = now + # http://diveintomark.org/archives/2004/05/28/howto-atom-id + news.guid = 'tag:%s,%s:%s' % (Site.objects.get_current(), + now.strftime('%Y-%m-%d'), news.get_absolute_url()) + # connect signals needed to keep cache in line with reality from main.utils import refresh_news_latest -from django.db.models.signals import post_save +from django.db.models.signals import pre_save, post_save + post_save.connect(refresh_news_latest, sender=News, dispatch_uid="news.models") +pre_save.connect(set_news_fields, sender=News, + dispatch_uid="news.models") # vim: set ts=4 sw=4 et: diff --git a/templates/feeds/news_description.html b/templates/feeds/news_description.html index a1e6446..e75d0af 100644 --- a/templates/feeds/news_description.html +++ b/templates/feeds/news_description.html @@ -1,3 +1,3 @@ {% load markup %} <p>{{obj.author.get_full_name}} wrote:</p> -{{ obj.content|markdown }} +{{ obj.content|markdown }}
\ No newline at end of file diff --git a/templates/feeds/news_title.html b/templates/feeds/news_title.html index d355de5..7899fce 100644 --- a/templates/feeds/news_title.html +++ b/templates/feeds/news_title.html @@ -1 +1 @@ -{{ obj.title }} +{{ obj.title }}
\ No newline at end of file diff --git a/templates/feeds/packages_description.html b/templates/feeds/packages_description.html index 6b9c47b..cfc4261 100644 --- a/templates/feeds/packages_description.html +++ b/templates/feeds/packages_description.html @@ -1 +1 @@ -{{ obj.pkgdesc }} +{{ obj.pkgdesc }}
\ No newline at end of file diff --git a/templates/feeds/packages_title.html b/templates/feeds/packages_title.html index 5c54ba6..f92ac68 100644 --- a/templates/feeds/packages_title.html +++ b/templates/feeds/packages_title.html @@ -1 +1 @@ -{{ obj.pkgname }} {{ obj.full_version }} {{ obj.arch.name }} +{{ obj.pkgname }} {{ obj.full_version }} {{ obj.arch.name }}
\ No newline at end of file |