From d394b2c40ee94394679700e5ff2858e1c95c7262 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Wed, 22 May 2013 23:46:09 +0200 Subject: Add Feed to the database Instead of specifying the feeds to use in the `local_settings.py' file specify them with the django admin interface. This means that the `django.contrib.admin', `django.contrib.auth' and all their dependencies have been added to the project. --- ryuslash/aggregator/admin.py | 5 ++ .../aggregator/management/commands/loadfeeds.py | 53 ++++++++++------------ ryuslash/aggregator/migrations/0001_initial.py | 45 ++++++++++++++---- ryuslash/aggregator/models.py | 20 +++++++- ryuslash/aggregator/views.py | 11 ++++- ryuslash/settings.py | 15 ++++-- ryuslash/urls.py | 15 ++++-- 7 files changed, 112 insertions(+), 52 deletions(-) create mode 100644 ryuslash/aggregator/admin.py diff --git a/ryuslash/aggregator/admin.py b/ryuslash/aggregator/admin.py new file mode 100644 index 0000000..ce27c1d --- /dev/null +++ b/ryuslash/aggregator/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin + +from aggregator.models import Feed + +admin.site.register(Feed) diff --git a/ryuslash/aggregator/management/commands/loadfeeds.py b/ryuslash/aggregator/management/commands/loadfeeds.py index 035e2ef..aba82c1 100644 --- a/ryuslash/aggregator/management/commands/loadfeeds.py +++ b/ryuslash/aggregator/management/commands/loadfeeds.py @@ -8,7 +8,7 @@ import urllib2 from django.conf import settings from django.core.management.base import BaseCommand -from aggregator.models import Post +from aggregator.models import Feed, Post class Command(BaseCommand): @@ -18,50 +18,42 @@ class Command(BaseCommand): value = re.sub('[^\w\s-]', '', value).strip().lower() return re.sub('[-\s]+', '-', value) - def get_ext(self, options): - if 'favicon_ext' in options.keys(): - return options['favicon_ext'] - else: - return 'ico' - - def get_logopath(self, feedname, options): - ext = self.get_ext(options) - filename = self.prep_feedname(feedname) + '.' + ext + def get_logopath(self, feed): + ext = feed.favicon_ext + filename = self.prep_feedname(feed.name) + '.' + ext basedir = settings.STATICFILES_DIRS[0] return os.path.join(basedir, 'images/logos', filename) - def have_logo(self, feedname, options): - logopath = self.get_logopath(feedname, options) + def have_logo(self, feed): + logopath = self.get_logopath(feed) return os.path.exists(logopath) - def save_logo(self, feedname, options): - ext = self.get_ext(options) - url = options['base_url'] + '/favicon.' + ext + def save_logo(self, feed): + ext = feed.favicon_ext + url = feed.base_url + '/favicon.' + ext try: logo = urllib2.urlopen(url) except: return - save = open(self.get_logopath(feedname, options), 'w') + save = open(self.get_logopath(feed), 'w') save.write(logo.read()) save.close() logo.close() def construct_feed_url(self, feed): - return feed['base_url'] + feed['feed_url'] + return feed.base_url + feed.feed_url def handle(self, *args, **kwargs): - for feedname, feedoptions in settings.FEEDS.iteritems(): - parsed = \ - feedparser.parse(self.construct_feed_url(feedoptions)) - icon = (self.prep_feedname(feedname) + '.' + - self.get_ext(feedoptions)) + for feed in Feed.objects.all(): + parsed = feedparser.parse(self.construct_feed_url(feed)) + icon = self.prep_feedname(feed.name) + '.' + feed.favicon_ext newcount = 0 - if not self.have_logo(feedname, feedoptions): - self.save_logo(feedname, feedoptions) + if not self.have_logo(feed): + self.save_logo(feed) for entry in parsed.entries: if Post.objects.filter(post_id=entry.id).exists(): @@ -81,23 +73,24 @@ class Command(BaseCommand): else: content = entry.summary - if feedoptions['markdown']: + if feed.uses_markdown: content = markdown.markdown(content) - if feedoptions.get('nl2br'): + if feed.convert_newlines: content = re.sub('\n', '
\n', content) post = Post( post_id=entry.id, - title=entry.title if feedoptions.get('title') else '', - category=feedoptions['category'], + title=entry.title if feed.uses_titles else '', + category=feed.category, link=entry.link, updated=updated, icon=icon, - content=content + content=content, + feed=feed ) post.save() newcount += 1 - print 'Grabbed %d new feeds from %s' % (newcount, feedname) + print 'Grabbed %d new posts from %s' % (newcount, feed.name) diff --git a/ryuslash/aggregator/migrations/0001_initial.py b/ryuslash/aggregator/migrations/0001_initial.py index 550a389..6bad6fb 100644 --- a/ryuslash/aggregator/migrations/0001_initial.py +++ b/ryuslash/aggregator/migrations/0001_initial.py @@ -8,31 +8,60 @@ from django.db import models class Migration(SchemaMigration): def forwards(self, orm): + # Adding model 'Feed' + db.create_table(u'aggregator_feed', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=300)), + ('base_url', self.gf('django.db.models.fields.URLField')(max_length=200)), + ('feed_url', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('favicon_ext', self.gf('django.db.models.fields.CharField')(default='ico', max_length=10)), + ('uses_markdown', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('uses_titles', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('convert_newlines', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('category', self.gf('django.db.models.fields.SmallIntegerField')()), + )) + db.send_create_signal(u'aggregator', ['Feed']) + # Adding model 'Post' - db.create_table('aggregator_post', ( + db.create_table(u'aggregator_post', ( ('post_id', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255, primary_key=True)), - ('title', self.gf('django.db.models.fields.CharField')(max_length=500)), - ('category', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=500, blank=True)), ('link', self.gf('django.db.models.fields.URLField')(max_length=255)), ('updated', self.gf('django.db.models.fields.DateTimeField')()), ('content', self.gf('django.db.models.fields.TextField')()), ('icon', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('feed', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['aggregator.Feed'])), )) - db.send_create_signal('aggregator', ['Post']) + db.send_create_signal(u'aggregator', ['Post']) def backwards(self, orm): + # Deleting model 'Feed' + db.delete_table(u'aggregator_feed') + # Deleting model 'Post' - db.delete_table('aggregator_post') + db.delete_table(u'aggregator_post') models = { - 'aggregator.post': { + u'aggregator.feed': { + 'Meta': {'object_name': 'Feed'}, + 'base_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), + 'category': ('django.db.models.fields.SmallIntegerField', [], {}), + 'convert_newlines': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'favicon_ext': ('django.db.models.fields.CharField', [], {'default': "'ico'", 'max_length': '10'}), + 'feed_url': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'uses_markdown': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'uses_titles': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + u'aggregator.post': { 'Meta': {'ordering': "['-updated']", 'object_name': 'Post'}, - 'category': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'content': ('django.db.models.fields.TextField', [], {}), + 'feed': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['aggregator.Feed']"}), 'icon': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'link': ('django.db.models.fields.URLField', [], {'max_length': '255'}), 'post_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'primary_key': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), 'updated': ('django.db.models.fields.DateTimeField', [], {}) } } diff --git a/ryuslash/aggregator/models.py b/ryuslash/aggregator/models.py index ac3d278..3ca7df2 100644 --- a/ryuslash/aggregator/models.py +++ b/ryuslash/aggregator/models.py @@ -1,14 +1,30 @@ from django.db import models + +class Feed(models.Model): + name = models.CharField(max_length=300) + base_url = models.URLField() + feed_url = models.CharField(max_length=100) + favicon_ext = models.CharField(max_length=10, default='ico') + uses_markdown = models.BooleanField() + uses_titles = models.BooleanField() + convert_newlines = models.BooleanField() + category = models.SmallIntegerField(choices=((0, 'post'), + (1, 'activity'))) + + def __unicode__(self): + return self.name + + class Post(models.Model): post_id = models.CharField(max_length=255, unique=True, primary_key=True) title = models.CharField(max_length=500, blank=True) - category = models.CharField(max_length=255) link = models.URLField(max_length=255) updated = models.DateTimeField() content = models.TextField() icon = models.CharField(max_length=255) + feed = models.ForeignKey(Feed) class Meta: - ordering = [ '-updated' ] + ordering = ['-updated'] diff --git a/ryuslash/aggregator/views.py b/ryuslash/aggregator/views.py index 80eaadd..e16be11 100644 --- a/ryuslash/aggregator/views.py +++ b/ryuslash/aggregator/views.py @@ -5,9 +5,16 @@ from django.shortcuts import render from aggregator.models import Post +def _get_category(cat): + if cat == 'activity': + return 1 + else: + return 0 + + def posts(request, cat, page=1): - category = cat or 'post' - queryset = Post.objects.filter(category=category) + category = _get_category(cat) + queryset = Post.objects.filter(feed__category=category) paginator = Paginator(queryset, 20) if page is None: diff --git a/ryuslash/settings.py b/ryuslash/settings.py index c5eecee..4d86769 100644 --- a/ryuslash/settings.py +++ b/ryuslash/settings.py @@ -70,11 +70,16 @@ TEMPLATE_DIRS = ( # Don't forget to use absolute paths, not relative paths. ) -INSTALLED_APPS = ('django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.staticfiles', - 'aggregator', - 'south') +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.staticfiles', + 'django.contrib.messages', + 'django.contrib.admin', + 'aggregator', + 'south' +) # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to diff --git a/ryuslash/urls.py b/ryuslash/urls.py index 917f2e9..a81f4c7 100644 --- a/ryuslash/urls.py +++ b/ryuslash/urls.py @@ -1,11 +1,16 @@ -from django.conf.urls import patterns, url +from django.conf.urls import include, patterns, url +from django.contrib import admin from django.contrib.staticfiles.urls import staticfiles_urlpatterns from aggregator.feeds import LatestPostsFeed -urlpatterns = patterns('', - url(r'^((?P[a-z_-]+)/)?((?P\d+)/)?$', - 'aggregator.views.posts'), - url(r'^feed/posts/$', LatestPostsFeed())) +admin.autodiscover() + +urlpatterns = patterns( + '', + url(r'^admin/', include(admin.site.urls)), + url(r'^((?P[a-z_-]+)/)?((?P\d+)/)?$', 'aggregator.views.posts'), + url(r'^feed/posts/$', LatestPostsFeed()), +) urlpatterns += staticfiles_urlpatterns() -- cgit v1.2.3-54-g00ecf