fmartingr
/
shelfzilla
Archived
1
0
Fork 0

Added base blog app

This commit is contained in:
Felipe Martín 2014-09-14 21:13:31 +02:00
parent 8ad0e87c18
commit 9e404aeb9b
17 changed files with 542 additions and 0 deletions

View File

@ -20,3 +20,6 @@ psycopg2==2.5.2
# Files
django-filer==0.9.5
# Blog
django-ckeditor-updated==4.4.0

View File

View File

@ -0,0 +1,72 @@
from django.contrib import admin
from .models import Entry, Tag
from django import forms
from django.utils.translation import ugettext as _
from django import forms
from django.db import models
from ckeditor.widgets import CKEditorWidget
import reversion
#
# ENTRY
#
class EntryAdmin(reversion.VersionAdmin):
list_display = ('title', 'date', 'status', 'tag_list', 'preview_link')
list_display_links = ('title', )
list_filter = ('date', 'draft', )
search_fields = ('title', 'content', )
prepopulated_fields = {"slug": ("title",)}
suit_form_tabs = (
('general', _('General')),
('content', _('Content')),
)
fieldsets = [
(None, {
'classes': ('suit-tab suit-tab-general',),
'fields': ('title', 'slug', 'draft', 'date', 'tags', )
}),
(None, {
'classes': ('suit-tab suit-tab-content full-width',),
'fields': ('content', )
}),
]
def preview_link(self, obj):
return '<a href="%s">View &raquo;</a>' % (
obj.get_absolute_url()
)
preview_link.allow_tags = True
def tag_list(self, obj):
return ", ".join([x.name for x in obj.tags.all()])
def save_model(self, request, obj, form, change):
if not change:
obj.author = request.user
super(self.__class__, self).save_model(request, obj, form, change)
class Media:
#css = {
# "all": ("ckeditor/redactor.css",)
#}
# js = (
# "ckeditor/ckeditor.js",
# "js/wysiwyg.js",
# )
pass
admin.site.register(Entry, EntryAdmin)
#
# TAG
#
class TagAdmin(reversion.VersionAdmin):
pass
admin.site.register(Tag, TagAdmin)

View File

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Entry'
db.create_table(u'blog_entry', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=128)),
('date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2014, 9, 4, 0, 0))),
('content', self.gf('ckeditor.fields.RichTextField')()),
('slug', self.gf('django.db.models.fields.SlugField')(max_length=128)),
('draft', self.gf('django.db.models.fields.BooleanField')(default=True)),
('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='author', to=orm['auth.User'])),
))
db.send_create_signal('blog', ['Entry'])
# Adding M2M table for field tags on 'Entry'
m2m_table_name = db.shorten_name(u'blog_entry_tags')
db.create_table(m2m_table_name, (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('entry', models.ForeignKey(orm['blog.entry'], null=False)),
('tag', models.ForeignKey(orm['blog.tag'], null=False))
))
db.create_unique(m2m_table_name, ['entry_id', 'tag_id'])
# Adding model 'Tag'
db.create_table(u'blog_tag', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=128)),
('color', self.gf('django.db.models.fields.CharField')(max_length=6, blank=True)),
))
db.send_create_signal('blog', ['Tag'])
def backwards(self, orm):
# Deleting model 'Entry'
db.delete_table(u'blog_entry')
# Removing M2M table for field tags on 'Entry'
db.delete_table(db.shorten_name(u'blog_entry_tags'))
# Deleting model 'Tag'
db.delete_table(u'blog_tag')
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
u'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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'blog.entry': {
'Meta': {'ordering': "['-date']", 'object_name': 'Entry'},
'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'to': u"orm['auth.User']"}),
'content': ('ckeditor.fields.RichTextField', [], {}),
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 9, 4, 0, 0)'}),
'draft': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '128'}),
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['blog.Tag']", 'null': 'True', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
},
'blog.tag': {
'Meta': {'ordering': "['name']", 'object_name': 'Tag'},
'color': ('django.db.models.fields.CharField', [], {'max_length': '6', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '128'})
},
u'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'}),
u'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'})
}
}
complete_apps = ['blog']

View File

@ -0,0 +1,71 @@
from django.db import models
from django.conf import settings
from datetime import datetime
from django.utils.timezone import utc
from ckeditor.fields import RichTextField
from django.core.urlresolvers import reverse
from django.utils.translation import activate
#
# ENTRY
#
class Entry(models.Model):
title = models.CharField(max_length=128)
date = models.DateTimeField(default=datetime.now(tz=utc))
content = RichTextField()
slug = models.SlugField(max_length=128)
draft = models.BooleanField(default=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
editable=False,
related_name='author'
)
tags = models.ManyToManyField('Tag', null=True, blank=True)
def __unicode__(self):
return self.title
def status(self):
status = 'Published'
if self.date > datetime.now(tz=utc):
status = 'Scheduled'
if self.draft:
status = 'Draft'
return status
def get_absolute_url(self):
kwargs = {
'year': self.date.year,
'month': self.date.strftime("%m"),
'day': self.date.strftime("%d"),
'slug': self.slug
}
url = reverse('blog:item', kwargs=kwargs)
return url
class Meta:
app_label = 'blog'
ordering = ['-date']
verbose_name_plural = 'Entries'
#
# TAG
#
class Tag(models.Model):
name = models.CharField(max_length=128)
color = models.CharField(max_length=6, blank=True)
def __unicode__(self):
return self.name
class Meta:
app_label = 'blog'
ordering = ['name']

View File

@ -0,0 +1,16 @@
from datetime import datetime
from django.contrib.sitemaps import Sitemap
from .models import Entry
class BlogSitemap(Sitemap):
changefreq = "monthly"
priority = 0.5
def items(self):
return Entry.objects.filter(draft=False, date__lte=datetime.now())
def lastmod(self, obj):
return obj.date

View File

@ -0,0 +1,10 @@
from django_jinja import library
from fmartingrcom.apps.config.models import SiteConfiguration
@library.filter
def readmore(content):
config = SiteConfiguration.objects.get()
summary, rest = content.split(config.readmore_tag, 1)
return summary

View File

@ -0,0 +1,18 @@
from pytz import timezone
from django.utils.translation import ugettext as _
from django.utils.encoding import smart_unicode
from django.conf import settings
from django_jinja import library
@library.filter
def dt(t, fmt=None):
"""
Call ``datetime.strftime`` with the given format string.
"""
tz = timezone(settings.TIME_ZONE)
if fmt is None:
fmt = _('%B %e, %Y')
return smart_unicode(tz.normalize(t).strftime(fmt)) if t else u''

View File

@ -0,0 +1,38 @@
from django.conf.urls import patterns, url
from .views import ListView, EntryView, SearchView, RSSView
urlpatterns = patterns(
None,
# Post list with page
url(
r'^page/(?P<page_number>\d+)/$',
ListView.as_view(),
name='list'
),
# Post list
url(
r'^$',
ListView.as_view(),
name='list'
),
# Single entry
url(
r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[\w\-]+)/$',
EntryView.as_view(),
name='item'
),
# RSS
url(
r'^rss\.xml$',
RSSView.as_view(),
name='rss'
),
# Search
url(
r'^search/$',
SearchView.as_view(),
name='search',
)
)

View File

@ -0,0 +1,55 @@
from datetime import datetime
from django.core.paginator import Paginator
from django.utils import translation
from django.conf import settings
from django.core.paginator import Paginator
from django.db.models import Q
from .models import Entry
class Config(object):
entries_per_page = 10
config = Config()
def get_posts(query=None, limit=None):
items = Entry.objects.filter(
draft=False,
date__lt=datetime.now()
)
if query and len(query) > 0:
items = items.filter(
Q(title__icontains=query) | \
Q(content__icontains=query) | \
Q(tags__name__iexact=query)
).distinct()
items = items.order_by('-date')
if limit:
items = items[:limit]
return items
def get_paginator(request, page_number=1, item=None, **kwargs):
item_index = None
page = None
items = get_posts(query=kwargs.get('query', None))
entries_per_page = config.entries_per_page
paginator = Paginator(items, entries_per_page)
if item:
for index, obj in enumerate(items):
if obj == item:
item_index = index
break
if item_index:
page_number = (item_index / entries_per_page) + 1
if page_number:
page = paginator.page(page_number)
return paginator, page

View File

@ -0,0 +1,103 @@
from datetime import datetime
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.conf import settings
from shelfzilla.views import View
import utils as blog_utils
from .models import Entry
class ListView(View):
section = 'blog'
template = 'blog/list.html'
def get(self, request, page_number=1):
if 'page' in request.GET:
page_number = int(request.GET['page'])
paginator, page = blog_utils.get_paginator(request, page_number)
context = {}
context['page'] = page
context['page_number'] = page_number
context['paginator'] = paginator
context = RequestContext(request, context)
return render_to_response(self.template, context_instance=context)
class EntryView(View):
section = 'blog'
template = 'blog/entry.jinja'
def get(self, request, year, month, day, slug):
try:
filters = {
'slug': slug,
'date__year': int(year),
'date__month': int(month),
'date__day': int(day),
}
item = Entry.objects.get(**filters)
except Entry.DoesNotExist:
raise Http404
paginator, page = blog_utils.get_paginator(request, item=item)
context = {}
context['page'] = page
context['paginator'] = paginator
context['item'] = item
context = RequestContext(request, context)
return render_to_response(self.template, context_instance=context)
class SearchView(ListView):
template = 'blog/search.jinja'
def post(self, request):
page_number = 1
if 'page' in request.GET:
page_number = int(request.GET['page'])
search_query = request.POST['query']
if not search_query:
return HttpResponseRedirect(reverse('blog:list'))
paginator, page = blog_utils.get_paginator(
request, page_number, query=search_query
)
context = {}
context['page'] = page
context['page_number'] = page_number
context['paginator'] = paginator
context['search_query'] = search_query
context = RequestContext(request, context)
return render_to_response(self.template, context_instance=context)
class RSSView(View):
template = 'blog/rss.jinja'
def get(self, request):
limit = 20
items = blog_utils.get_posts(limit=limit)
context = {}
context['items'] = items
context = RequestContext(request, context)
return render_to_response(
'blog/rss.jinja',
context_instance=context,
mimetype='text/xml'
)

View File

@ -58,6 +58,7 @@ INSTALLED_APPS = (
# Staticfiles
"compressor",
'ckeditor',
# Apps
'shelfzilla.apps._admin',
@ -66,6 +67,7 @@ INSTALLED_APPS = (
'shelfzilla.apps.homepage',
'shelfzilla.apps.landing',
'shelfzilla.apps.manga',
'shelfzilla.apps.blog',
'shelfzilla.apps.pjax',
)
@ -261,6 +263,11 @@ SUIT_CONFIG = {
'label': 'Settings',
'icon': 'icon-cog',
},
{
'app': 'blog',
'label': 'Blog',
'icon': 'icon-book',
},
{
'app': 'manga',
'label': 'Manga',
@ -273,3 +280,15 @@ SUIT_CONFIG = {
},
),
}
#
# CKEDITOR
#
CKEDITOR_UPLOAD_PATH = 'ckeditor/'
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'Standard',
'width': '100%',
},
}

View File

@ -0,0 +1,3 @@
{% extends "_layout.html" %}
{% block page_title %}{{ block.super }} | Blog{% endblock %}

View File

@ -0,0 +1,24 @@
{% extends "blog/_layout.html" %}
{% load i18n %}
{% block main_content %}
<div class="container">
<ul class="media-list">
{% for item in page.object_list %}
<li class="media well {% if item.draft %}draft{% endif %}">
<a class="pull-left" href="#">
<!--<img class="media-object img-rounded" src="{{ item.author.avatar }}">-->
</a>
<div class="media-body">
<h2 class="media-heading">{{ item.title }}</h2>
<div>
Por <strong>{{ item.author.first_name }}</strong> el
<time datetime="{{ item.date }}" pubdate="" data-updated="true">{{ item.date }}</time>
</div>
<p>{{ item.content|safe }}</p>
</div>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}

View File

@ -9,10 +9,12 @@ admin.autodiscover()
urlpatterns = patterns(
'',
url(r'^ckeditor/', include('ckeditor.urls')),
url(r'^messages/$', MessagesView.as_view(), name="contrib.messages"),
url(r'^$', include('shelfzilla.apps.homepage.urls')),
url(r'^', include('shelfzilla.apps.landing.urls')),
url(r'^', include('shelfzilla.apps.users.urls')),
url(r'^blog/', include('shelfzilla.apps.blog.urls', namespace='blog')),
url(r'^series/', include('shelfzilla.apps.manga.urls.series')),
url(r'^volumes/', include('shelfzilla.apps.manga.urls.volumes')),
url(r'^publishers/', include('shelfzilla.apps.manga.urls.publishers')),