mirror of https://github.com/scrapy/scrapy.git
using a modified version of django simple blog
--HG-- extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%40572
This commit is contained in:
parent
a5b609ac5f
commit
48682189b4
|
|
@ -0,0 +1,17 @@
|
|||
from django.contrib import admin
|
||||
from scrapyorg.blog.models import *
|
||||
|
||||
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
|
||||
admin.site.register(Category, CategoryAdmin)
|
||||
|
||||
|
||||
class PostAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'publish', 'status')
|
||||
list_filter = ('publish', 'categories', 'status')
|
||||
search_fields = ('title', 'body')
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
|
||||
admin.site.register(Post, PostAdmin)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
from django.contrib.syndication.feeds import FeedDoesNotExist
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.contrib.sites.models import Site
|
||||
from django.contrib.syndication.feeds import Feed
|
||||
from django.core.urlresolvers import reverse
|
||||
from scrapyorg.blog.models import Post, Category
|
||||
|
||||
|
||||
class BlogPostsFeed(Feed):
|
||||
_site = Site.objects.get_current()
|
||||
title = '%s feed' % _site.name
|
||||
description = '%s posts feed.' % _site.name
|
||||
|
||||
def link(self):
|
||||
return reverse('blog_index')
|
||||
|
||||
def items(self):
|
||||
return Post.objects.published()[:10]
|
||||
|
||||
def item_pubdate(self, obj):
|
||||
return obj.publish
|
||||
|
||||
|
||||
class BlogPostsByCategory(Feed):
|
||||
_site = Site.objects.get_current()
|
||||
title = '%s posts category feed' % _site.name
|
||||
|
||||
def get_object(self, bits):
|
||||
if len(bits) != 1:
|
||||
raise ObjectDoesNotExist
|
||||
return Category.objects.get(slug__exact=bits[0])
|
||||
|
||||
def link(self, obj):
|
||||
if not obj:
|
||||
raise FeedDoesNotExist
|
||||
return obj.get_absolute_url()
|
||||
|
||||
def description(self, obj):
|
||||
return "Posts recently categorized as %s" % obj.title
|
||||
|
||||
def items(self, obj):
|
||||
return obj.post_set.published()[:10]
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from django.db.models import Manager
|
||||
import datetime
|
||||
|
||||
|
||||
class PublicManager(Manager):
|
||||
"""Returns published posts that are not in the future."""
|
||||
|
||||
def published(self):
|
||||
return self.get_query_set().filter(status__gte=2, publish__lte=datetime.datetime.now())
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import permalink
|
||||
from django.contrib.auth.models import User
|
||||
#from tagging.fields import TagField
|
||||
from scrapyorg.blog.managers import PublicManager
|
||||
|
||||
#import tagging
|
||||
|
||||
|
||||
class Category(models.Model):
|
||||
"""Category model."""
|
||||
title = models.CharField(_('title'), max_length=100)
|
||||
slug = models.SlugField(_('slug'), unique=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('category')
|
||||
verbose_name_plural = _('categories')
|
||||
db_table = 'blog_categories'
|
||||
ordering = ('title',)
|
||||
|
||||
class Admin:
|
||||
pass
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s' % self.title
|
||||
|
||||
@permalink
|
||||
def get_absolute_url(self):
|
||||
return ('blog_category_detail', None, {'slug': self.slug})
|
||||
|
||||
|
||||
class Post(models.Model):
|
||||
"""Post model."""
|
||||
STATUS_CHOICES = (
|
||||
(1, _('Draft')),
|
||||
(2, _('Public')),
|
||||
)
|
||||
title = models.CharField(_('title'), max_length=200)
|
||||
slug = models.SlugField(_('slug'), unique_for_date='publish')
|
||||
author = models.ForeignKey(User, blank=True, null=True)
|
||||
body = models.TextField(_('body'))
|
||||
tease = models.TextField(_('tease'), blank=True)
|
||||
status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=2)
|
||||
allow_comments = models.BooleanField(_('allow comments'), default=True)
|
||||
publish = models.DateTimeField(_('publish'))
|
||||
created = models.DateTimeField(_('created'), auto_now_add=True)
|
||||
modified = models.DateTimeField(_('modified'), auto_now=True)
|
||||
categories = models.ManyToManyField(Category, blank=True)
|
||||
# tags = TagField()
|
||||
objects = PublicManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('post')
|
||||
verbose_name_plural = _('posts')
|
||||
db_table = 'blog_posts'
|
||||
ordering = ('-publish',)
|
||||
get_latest_by = 'publish'
|
||||
|
||||
class Admin:
|
||||
list_display = ('title', 'publish', 'status')
|
||||
list_filter = ('publish', 'categories', 'status')
|
||||
search_fields = ('title', 'body')
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s' % self.title
|
||||
|
||||
@permalink
|
||||
def get_absolute_url(self):
|
||||
return ('blog_detail', None, {
|
||||
'year': self.publish.year,
|
||||
'month': self.publish.strftime('%b').lower(),
|
||||
'day': self.publish.day,
|
||||
'slug': self.slug
|
||||
})
|
||||
|
||||
def get_previous_post(self):
|
||||
return self.get_previous_by_publish(status__gte=2)
|
||||
|
||||
def get_next_post(self):
|
||||
return self.get_next_by_publish(status__gte=2)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from django.contrib.sitemaps import Sitemap
|
||||
from scrapyorg.blog.models import Post
|
||||
|
||||
|
||||
class BlogSitemap(Sitemap):
|
||||
changefreq = "never"
|
||||
priority = 0.5
|
||||
|
||||
def items(self):
|
||||
return Post.objects.published()
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.publish
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
</head>
|
||||
<body id="{% block body_id %}{% endblock %}">
|
||||
<div id="body">
|
||||
{% block body %}
|
||||
<div>
|
||||
{% block content_title %}{% endblock %}
|
||||
</div>
|
||||
<div class="content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
oaihdasasihjsd
|
||||
|
||||
|
||||
{% block body_class %}blog{% endblock %}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Posts for {{ category.title }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} category_detail{% endblock %}
|
||||
{% block body_id %}category_{{ category.id }}{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Posts for {{ category.title }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% load markup %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post categories{% endblock %}
|
||||
{% block body_class %}{{ block.super }} category_list{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Post categories</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% load markup %}
|
||||
<ul class="link_list">
|
||||
{% for category in object_list %}
|
||||
<li><a href="{{ category.get_absolute_url }}">{{ category }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive for {{ day|date:"d F Y" }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_archive_day{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Post archive for {{ day|date:"d F Y" }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive for {{ month|date:"F Y" }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_archive_month{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Post archive for {{ month|date:"F Y" }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive for {{ year }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_archive_year{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Post archive for {{ year }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% load markup %}
|
||||
|
||||
<ul class="link_list">
|
||||
{% for month in date_list %}
|
||||
<li><a href="{% url blog_index %}{{ year }}/{{ month|date:"b" }}/">{{ month|date:"F" }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}{{ object.title }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_detail{% endblock %}
|
||||
{% block body_id %}post_{{ object.id }}{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>{{ object.title }}</h2>
|
||||
<p class="other_posts">
|
||||
{% if object.get_previous_by_publish %}
|
||||
<a class="previous" href="{{ object.get_previous_post.get_absolute_url }}">« {{ object.get_previous_post }}</a>
|
||||
{% endif %}
|
||||
{% if object.get_next_by_publish %}
|
||||
| <a class="next" href="{{ object.get_next_post.get_absolute_url }}">{{ object.get_next_post }} »</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% load blog markup comments tagging_tags %}
|
||||
|
||||
<p class="date">{{ object.publish|date:"j F Y" }}</p>
|
||||
|
||||
<div class="body">
|
||||
{{ object.body|markdown:"safe" }}
|
||||
</div>
|
||||
|
||||
{% tags_for_object object as tag_list %}
|
||||
{% if tag_list %}
|
||||
<p class="inline_tag_list"><strong>Related tags:</strong>
|
||||
{% for tag in tag_list %}
|
||||
{{ tag }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% get_comment_list for object as comment_list %}
|
||||
{% if comment_list %}
|
||||
<div id="comments">
|
||||
<a name="comments"></a>
|
||||
<h3 class="comments_title">Comments</h3>
|
||||
{% for comment in comment_list %}
|
||||
{% if comment.is_public %}
|
||||
<div class="comment">
|
||||
<h5 class="name">
|
||||
<a name="c{{ comment.id }}" href="{{ comment.get_absolute_url }}" title="Permalink to {{ comment.person_name }}'s comment" class="count">{{ forloop.counter }}</a>
|
||||
{% if comment.user_url %}<a href="{{ comment.user_url }}">{{ comment.user_name }}</a>{% else %}{{ comment.user_name }}{% endif %} says...
|
||||
</h5>
|
||||
{{ comment.comment|urlizetrunc:"60"|markdown:"safe" }}
|
||||
<p class="date">Posted at {{ comment.submit_date|date:"P" }} on {{ comment.submit_date|date:"F j, Y" }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if object.allow_comments %}
|
||||
{% render_comment_form for object %}
|
||||
{% else %}
|
||||
<div id="comment_form">
|
||||
<h3>Comments are closed.</h3>
|
||||
<p>Comments have been close for this post.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_list{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Post archive</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if is_paginated %}
|
||||
<p class="pagination">
|
||||
{% if has_next %}
|
||||
<a class="older" href="?page={{ next }}">Older</a>
|
||||
{% endif %}
|
||||
{% if has_next and has_previous %} | {% endif %}
|
||||
{% if has_previous %}
|
||||
<a class="newer" href="?page={{ previous }}">Newer</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post search{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_search{% endblock %}
|
||||
|
||||
|
||||
{% block content_title %}
|
||||
<h2>Search</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<form action="." method="get" id="post_search_form">
|
||||
<p>
|
||||
<input type="text" name="q" value="{{ search_term }}" id="search">
|
||||
<input type="submit" class="button" value="Search">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
{% if message %}
|
||||
<p class="message">{{ message }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if object_list %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
<p class="comments">{% if comment_count %}{{ comment_count }} comment{{ comment_count|pluralize }}{% endif %}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{{ obj.tease }}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{{ obj.title }}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
{% extends "admin/change_form.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
{% load adminmedia inlines %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
function InlineInit() {
|
||||
var body_div = document.getElementById('id_body').parentNode;
|
||||
var content = ''
|
||||
content += '{% get_inline_types as inline_list %}'
|
||||
content += '<label>Body inlines:</label>'
|
||||
|
||||
content += '<strong>Inline type:</strong> '
|
||||
content += '<select id="id_inline_content_type" onchange="document.getElementById(\'lookup_id_inline\').href = \'../../../\'+this.value+\'/\';" style="margin-right:20px;">'
|
||||
content += ' <option>----------</option>'
|
||||
content += ' {% for inline in inline_list %}'
|
||||
content += ' <option value="{{ inline.content_type.app_label }}/{{ inline.content_type.model }}">{{ inline.content_type.app_label|capfirst }}: {{ inline.content_type.model|capfirst }}</option>'
|
||||
content += ' {% endfor %}'
|
||||
content += '</select> '
|
||||
|
||||
content += '<strong>Object:</strong> '
|
||||
content += '<input type="text" class="vIntegerField" id="id_inline" size="10" /> '
|
||||
content += '<a id="lookup_id_inline" href="#" class="related-lookup" onclick="if(document.getElementById(\'id_inline_content_type\').value != \'----------\') { return showRelatedObjectLookupPopup(this); }" style="margin-right:20px;"><img src="{% admin_media_prefix %}img/admin/selector-search.gif" width="16" height="16" alt="Loopup" /></a> '
|
||||
|
||||
content += '<strong>Class:</strong> '
|
||||
content += '<select id="id_inline_class">'
|
||||
content += ' <option value="small_left">Small left</option>'
|
||||
content += ' <option value="small_right">Small right</option>'
|
||||
content += ' <option value="medium_left">Medium left</option>'
|
||||
content += ' <option value="medium_right">Medium right</option>'
|
||||
content += ' <option value="large_left">Large left</option>'
|
||||
content += ' <option value="large_right">Large right</option>'
|
||||
content += ' <option value="full">Full</option>'
|
||||
content += '</select>'
|
||||
|
||||
content += '<input type="button" value="Add" style="margin-left:10px;" onclick="return insertInline(document.getElementById(\'id_inline_content_type\').value, document.getElementById(\'id_inline\').value, document.getElementById(\'id_inline_class\').value)" />'
|
||||
content += '<p class="help">Insert inlines into your body by choosing an inline type, then an object, then a class.</p>'
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('style', 'margin-top:10px;');
|
||||
div.innerHTML = content;
|
||||
|
||||
body_div.insertBefore(div);
|
||||
}
|
||||
|
||||
function insertInline(type, id, classname) {
|
||||
if (type != '----------' && id != '') {
|
||||
inline = '<inline type="'+type.replace('/', '.')+'" id="'+id+'" class="'+classname+'" />';
|
||||
body = document.getElementById('id_body');
|
||||
body.value = body.value + inline + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
addEvent(window, 'load', InlineInit);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{% if object %}
|
||||
{{ object }}
|
||||
{% else %}
|
||||
{% for object in object_list %}
|
||||
{{ object }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
from django import template
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
import re
|
||||
|
||||
Post = models.get_model('blog', 'post')
|
||||
Category = models.get_model('blog', 'category')
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
class LatestPosts(template.Node):
|
||||
def __init__(self, limit, var_name):
|
||||
self.limit = limit
|
||||
self.var_name = var_name
|
||||
|
||||
def render(self, context):
|
||||
posts = Post.objects.published()[:int(self.limit)]
|
||||
if posts and (int(self.limit) == 1):
|
||||
context[self.var_name] = posts[0]
|
||||
else:
|
||||
context[self.var_name] = posts
|
||||
return ''
|
||||
|
||||
@register.tag
|
||||
def get_latest_posts(parser, token):
|
||||
"""
|
||||
Gets any number of latest posts and stores them in a varable.
|
||||
|
||||
Syntax::
|
||||
|
||||
{% get_latest_posts [limit] as [var_name] %}
|
||||
|
||||
Example usage::
|
||||
|
||||
{% get_latest_posts 10 as latest_post_list %}
|
||||
"""
|
||||
try:
|
||||
tag_name, arg = token.contents.split(None, 1)
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%s tag requires arguments" % token.contents.split()[0]
|
||||
m = re.search(r'(.*?) as (\w+)', arg)
|
||||
if not m:
|
||||
raise template.TemplateSyntaxError, "%s tag had invalid arguments" % tag_name
|
||||
format_string, var_name = m.groups()
|
||||
return LatestPosts(format_string, var_name)
|
||||
|
||||
|
||||
class BlogCategories(template.Node):
|
||||
def __init__(self, var_name):
|
||||
self.var_name = var_name
|
||||
|
||||
def render(self, context):
|
||||
categories = Category.objects.all()
|
||||
context[self.var_name] = categories
|
||||
return ''
|
||||
|
||||
@register.tag
|
||||
def get_blog_categories(parser, token):
|
||||
"""
|
||||
Gets all blog categories.
|
||||
|
||||
Syntax::
|
||||
|
||||
{% get_blog_categories as [var_name] %}
|
||||
|
||||
Example usage::
|
||||
|
||||
{% get_blog_categories as category_list %}
|
||||
"""
|
||||
try:
|
||||
tag_name, arg = token.contents.split(None, 1)
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%s tag requires arguments" % token.contents.split()[0]
|
||||
m = re.search(r'as (\w+)', arg)
|
||||
if not m:
|
||||
raise template.TemplateSyntaxError, "%s tag had invalid arguments" % tag_name
|
||||
var_name = m.groups()[0]
|
||||
return BlogCategories(var_name)
|
||||
|
||||
|
||||
@register.filter
|
||||
def get_links(value):
|
||||
"""
|
||||
Extracts links from a ``Post`` body and returns a list.
|
||||
|
||||
Template Syntax::
|
||||
|
||||
{{ post.body|markdown:"safe"|get_links }}
|
||||
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
except ImportError:
|
||||
from beautifulsoup import BeautifulSoup
|
||||
soup = BeautifulSoup(value)
|
||||
return soup.findAll('a')
|
||||
except ImportError:
|
||||
if settings.DEBUG:
|
||||
raise template.TemplateSyntaxError, "Error in 'get_links' filter: BeautifulSoup isn't installed."
|
||||
return value
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
"""
|
||||
>>> from django.test import Client
|
||||
>>> from scrapyorg.blog.models import Post, Category
|
||||
>>> import datetime
|
||||
>>> from django.core.urlresolvers import reverse
|
||||
>>> client = Client()
|
||||
|
||||
>>> category = Category(title='Django', slug='django')
|
||||
>>> category.save()
|
||||
>>> category2 = Category(title='Rails', slug='rails')
|
||||
>>> category2.save()
|
||||
|
||||
>>> post = Post(title='DJ Ango', slug='dj-ango', body='Yo DJ! Turn that music up!', status=2, publish=datetime.datetime(2008,5,5,16,20))
|
||||
>>> post.save()
|
||||
|
||||
>>> post2 = Post(title='Where my grails at?', slug='where', body='I Can haz Holy plez?', status=2, publish=datetime.datetime(2008,4,2,11,11))
|
||||
>>> post2.save()
|
||||
|
||||
>>> post.categories.add(category)
|
||||
>>> post2.categories.add(category2)
|
||||
|
||||
>>> response = client.get(reverse('blog_index'))
|
||||
>>> response.context[-1]['object_list']
|
||||
[<Post: DJ Ango>, <Post: Where my grails at?>]
|
||||
>>> response.status_code
|
||||
200
|
||||
|
||||
>>> response = client.get(reverse('blog_category_list'))
|
||||
>>> response.context[-1]['object_list']
|
||||
[<Category: Django>, <Category: Rails>]
|
||||
>>> response.status_code
|
||||
200
|
||||
|
||||
>>> response = client.get(category.get_absolute_url())
|
||||
>>> response.context[-1]['object_list']
|
||||
[<Post: DJ Ango>]
|
||||
>>> response.status_code
|
||||
200
|
||||
|
||||
>>> response = client.get(post.get_absolute_url())
|
||||
>>> response.context[-1]['object']
|
||||
<Post: DJ Ango>
|
||||
>>> response.status_code
|
||||
200
|
||||
|
||||
>>> response = client.get(reverse('blog_search'), {'q': 'DJ'})
|
||||
>>> response.context[-1]['object_list']
|
||||
[<Post: DJ Ango>]
|
||||
>>> response.status_code
|
||||
200
|
||||
>>> response = client.get(reverse('blog_search'), {'q': 'Holy'})
|
||||
>>> response.context[-1]['object_list']
|
||||
[<Post: Where my grails at?>]
|
||||
>>> response.status_code
|
||||
200
|
||||
>>> response = client.get(reverse('blog_search'), {'q': ''})
|
||||
>>> response.context[-1]['message']
|
||||
'Search term was too vague. Please try again.'
|
||||
|
||||
>>> response = client.get(reverse('blog_detail', args=[2008, 'apr', 2, 'where']))
|
||||
>>> response.context[-1]['object']
|
||||
<Post: Where my grails at?>
|
||||
>>> response.status_code
|
||||
200
|
||||
"""
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
from django.conf.urls.defaults import *
|
||||
from scrapyorg.blog import views as blog_views
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^(?P<year>\d{4})/(?P<month>\w{3})/(?P<day>\d{1,2})/(?P<slug>[-\w]+)/$',
|
||||
view=blog_views.post_detail,
|
||||
name='blog_detail'),
|
||||
|
||||
url(r'^(?P<year>\d{4})/(?P<month>\w{3})/(?P<day>\d{1,2})/$',
|
||||
view=blog_views.post_archive_day,
|
||||
name='blog_archive_day'),
|
||||
|
||||
url(r'^(?P<year>\d{4})/(?P<month>\w{3})/$',
|
||||
view=blog_views.post_archive_month,
|
||||
name='blog_archive_month'),
|
||||
|
||||
url(r'^(?P<year>\d{4})/$',
|
||||
view=blog_views.post_archive_year,
|
||||
name='blog_archive_year'),
|
||||
|
||||
url(r'^categories/(?P<slug>[-\w]+)/$',
|
||||
view=blog_views.category_detail,
|
||||
name='blog_category_detail'),
|
||||
|
||||
url (r'^categories/$',
|
||||
view=blog_views.category_list,
|
||||
name='blog_category_list'),
|
||||
|
||||
url (r'^search/$',
|
||||
view=blog_views.search,
|
||||
name='blog_search'),
|
||||
|
||||
url(r'^page/(?P<page>\w)/$',
|
||||
view=blog_views.post_list,
|
||||
name='blog_index_paginated'),
|
||||
|
||||
url(r'^$',
|
||||
view=blog_views.post_list,
|
||||
name='blog_index'),
|
||||
)
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
from django.http import Http404
|
||||
from django.views.generic import date_based, list_detail
|
||||
from django.db.models import Q
|
||||
from scrapyorg.blog.models import *
|
||||
|
||||
import datetime
|
||||
import re
|
||||
|
||||
|
||||
def post_list(request, page=0, **kwargs):
|
||||
return list_detail.object_list(
|
||||
request,
|
||||
queryset = Post.objects.published(),
|
||||
paginate_by = 20,
|
||||
page = page,
|
||||
**kwargs
|
||||
)
|
||||
post_list.__doc__ = list_detail.object_list.__doc__
|
||||
|
||||
|
||||
def post_archive_year(request, year, **kwargs):
|
||||
return date_based.archive_year(
|
||||
request,
|
||||
year = year,
|
||||
date_field = 'publish',
|
||||
queryset = Post.objects.published(),
|
||||
make_object_list = True,
|
||||
**kwargs
|
||||
)
|
||||
post_archive_year.__doc__ = date_based.archive_year.__doc__
|
||||
|
||||
|
||||
def post_archive_month(request, year, month, **kwargs):
|
||||
return date_based.archive_month(
|
||||
request,
|
||||
year = year,
|
||||
month = month,
|
||||
date_field = 'publish',
|
||||
queryset = Post.objects.published(),
|
||||
**kwargs
|
||||
)
|
||||
post_archive_month.__doc__ = date_based.archive_month.__doc__
|
||||
|
||||
|
||||
def post_archive_day(request, year, month, day, **kwargs):
|
||||
return date_based.archive_day(
|
||||
request,
|
||||
year = year,
|
||||
month = month,
|
||||
day = day,
|
||||
date_field = 'publish',
|
||||
queryset = Post.objects.published(),
|
||||
**kwargs
|
||||
)
|
||||
post_archive_day.__doc__ = date_based.archive_day.__doc__
|
||||
|
||||
|
||||
def post_detail(request, slug, year, month, day, **kwargs):
|
||||
return date_based.object_detail(
|
||||
request,
|
||||
year = year,
|
||||
month = month,
|
||||
day = day,
|
||||
date_field = 'publish',
|
||||
slug = slug,
|
||||
queryset = Post.objects.published(),
|
||||
**kwargs
|
||||
)
|
||||
post_detail.__doc__ = date_based.object_detail.__doc__
|
||||
|
||||
|
||||
def category_list(request, template_name = 'blog/category_list.html', **kwargs):
|
||||
"""
|
||||
Category list
|
||||
|
||||
Template: ``blog/category_list.html``
|
||||
Context:
|
||||
object_list
|
||||
List of categories.
|
||||
"""
|
||||
return list_detail.object_list(
|
||||
request,
|
||||
queryset = Category.objects.all(),
|
||||
template_name = template_name,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def category_detail(request, slug, template_name = 'blog/category_detail.html', **kwargs):
|
||||
"""
|
||||
Category detail
|
||||
|
||||
Template: ``blog/category_detail.html``
|
||||
Context:
|
||||
object_list
|
||||
List of posts specific to the given category.
|
||||
category
|
||||
Given category.
|
||||
"""
|
||||
category = get_object_or_404(Category, slug__iexact=slug)
|
||||
|
||||
return list_detail.object_list(
|
||||
request,
|
||||
queryset = category.post_set.published(),
|
||||
extra_context = {'category': category},
|
||||
template_name = template_name,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
# Stop Words courtesy of http://www.dcs.gla.ac.uk/idom/ir_resources/linguistic_utils/stop_words
|
||||
STOP_WORDS = r"""\b(a|about|above|across|after|afterwards|again|against|all|almost|alone|along|already|also|
|
||||
although|always|am|among|amongst|amoungst|amount|an|and|another|any|anyhow|anyone|anything|anyway|anywhere|are|
|
||||
around|as|at|back|be|became|because|become|becomes|becoming|been|before|beforehand|behind|being|below|beside|
|
||||
besides|between|beyond|bill|both|bottom|but|by|call|can|cannot|cant|co|computer|con|could|couldnt|cry|de|describe|
|
||||
detail|do|done|down|due|during|each|eg|eight|either|eleven|else|elsewhere|empty|enough|etc|even|ever|every|everyone|
|
||||
everything|everywhere|except|few|fifteen|fify|fill|find|fire|first|five|for|former|formerly|forty|found|four|from|
|
||||
front|full|further|get|give|go|had|has|hasnt|have|he|hence|her|here|hereafter|hereby|herein|hereupon|hers|herself|
|
||||
him|himself|his|how|however|hundred|i|ie|if|in|inc|indeed|interest|into|is|it|its|itself|keep|last|latter|latterly|
|
||||
least|less|ltd|made|many|may|me|meanwhile|might|mill|mine|more|moreover|most|mostly|move|much|must|my|myself|name|
|
||||
namely|neither|never|nevertheless|next|nine|no|nobody|none|noone|nor|not|nothing|now|nowhere|of|off|often|on|once|
|
||||
one|only|onto|or|other|others|otherwise|our|ours|ourselves|out|over|own|part|per|perhaps|please|put|rather|re|same|
|
||||
see|seem|seemed|seeming|seems|serious|several|she|should|show|side|since|sincere|six|sixty|so|some|somehow|someone|
|
||||
something|sometime|sometimes|somewhere|still|such|system|take|ten|than|that|the|their|them|themselves|then|thence|
|
||||
there|thereafter|thereby|therefore|therein|thereupon|these|they|thick|thin|third|this|those|though|three|through|
|
||||
throughout|thru|thus|to|together|too|top|toward|towards|twelve|twenty|two|un|under|until|up|upon|us|very|via|was|
|
||||
we|well|were|what|whatever|when|whence|whenever|where|whereafter|whereas|whereby|wherein|whereupon|wherever|whether|
|
||||
which|while|whither|who|whoever|whole|whom|whose|why|will|with|within|without|would|yet|you|your|yours|yourself|
|
||||
yourselves)\b"""
|
||||
|
||||
|
||||
def search(request, template_name='blog/post_search.html'):
|
||||
"""
|
||||
Search for blog posts.
|
||||
|
||||
This template will allow you to setup a simple search form that will try to return results based on
|
||||
given search strings. The queries will be put through a stop words filter to remove words like
|
||||
'the', 'a', or 'have' to help imporve the result set.
|
||||
|
||||
Template: ``blog/post_search.html``
|
||||
Context:
|
||||
object_list
|
||||
List of blog posts that match given search term(s).
|
||||
search_term
|
||||
Given search term.
|
||||
"""
|
||||
context = {}
|
||||
if request.GET:
|
||||
stop_word_list = re.compile(STOP_WORDS, re.IGNORECASE)
|
||||
search_term = '%s' % request.GET['q']
|
||||
cleaned_search_term = stop_word_list.sub('', search_term)
|
||||
cleaned_search_term = cleaned_search_term.strip()
|
||||
if len(cleaned_search_term) != 0:
|
||||
post_list = Post.objects.published().filter(Q(body__icontains=cleaned_search_term) | Q(tags__icontains=cleaned_search_term) | Q(categories__title__icontains=cleaned_search_term))
|
||||
context = {'object_list': post_list, 'search_term':search_term}
|
||||
else:
|
||||
message = 'Search term was too vague. Please try again.'
|
||||
context = {'message':message}
|
||||
return render_to_response(template_name, context, context_instance=RequestContext(request))
|
||||
|
|
@ -77,9 +77,11 @@ INSTALLED_APPS = (
|
|||
'django.contrib.sites',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.markup',
|
||||
'django.contrib.comments',
|
||||
'scrapyorg.article',
|
||||
'scrapyorg.download',
|
||||
'scrapyorg.docs',
|
||||
'scrapyorg.blog',
|
||||
)
|
||||
|
||||
DOC_PICKLE_ROOT = os.path.join(PROJECT_ROOT, 'docs', 'pickle')
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ urlpatterns = patterns('',
|
|||
|
||||
# docs
|
||||
url(r"^docs/", include("scrapyorg.docs.urls")),
|
||||
# blog
|
||||
url(r"^blog/", include("scrapyorg.blog.urls")),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
oaihdasasihjsd
|
||||
|
||||
|
||||
{% block body_class %}blog{% endblock %}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Posts for {{ category.title }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} category_detail{% endblock %}
|
||||
{% block body_id %}category_{{ category.id }}{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Posts for {{ category.title }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
{% load markup %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post categories{% endblock %}
|
||||
{% block body_class %}{{ block.super }} category_list{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Post categories</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
{% load markup %}
|
||||
<ul class="link_list">
|
||||
{% for category in object_list %}
|
||||
<li><a href="{{ category.get_absolute_url }}">{{ category }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive for {{ day|date:"d F Y" }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_archive_day{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Post archive for {{ day|date:"d F Y" }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive for {{ month|date:"F Y" }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_archive_month{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Post archive for {{ month|date:"F Y" }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive for {{ year }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_archive_year{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Post archive for {{ year }}</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
{% load markup %}
|
||||
|
||||
<ul class="link_list">
|
||||
{% for month in date_list %}
|
||||
<li><a href="{% url blog_index %}{{ year }}/{{ month|date:"b" }}/">{{ month|date:"F" }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}{{ object.title }}{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_detail{% endblock %}
|
||||
{% block body_id %}post_{{ object.id }}{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>{{ object.title }}</h2>
|
||||
<p class="other_posts">
|
||||
{% if object.get_previous_by_publish %}
|
||||
<a class="previous" href="{{ object.get_previous_post.get_absolute_url }}">« {{ object.get_previous_post }}</a>
|
||||
{% endif %}
|
||||
{% if object.get_next_by_publish %}
|
||||
| <a class="next" href="{{ object.get_next_post.get_absolute_url }}">{{ object.get_next_post }} »</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
{% load blog markup comments %}
|
||||
{% comment %}
|
||||
{% load tagging_tags %}
|
||||
{% endcomment %}
|
||||
|
||||
<p class="date">{{ object.publish|date:"j F Y" }}</p>
|
||||
|
||||
<div class="body">
|
||||
{{ object.body|markdown:"safe" }}
|
||||
</div>
|
||||
|
||||
{% comment %}
|
||||
{% tags_for_object object as tag_list %}
|
||||
{% if tag_list %}
|
||||
<p class="inline_tag_list"><strong>Related tags:</strong>
|
||||
{% for tag in tag_list %}
|
||||
{{ tag }}{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endcomment %}
|
||||
|
||||
{% get_comment_list for object as comment_list %}
|
||||
{% if comment_list %}
|
||||
<div id="comments">
|
||||
<a name="comments"></a>
|
||||
<h3 class="comments_title">Comments</h3>
|
||||
{% for comment in comment_list %}
|
||||
{% if comment.is_public %}
|
||||
<div class="comment">
|
||||
<h5 class="name">
|
||||
<a name="c{{ comment.id }}" href="{{ comment.get_absolute_url }}" title="Permalink to {{ comment.person_name }}'s comment" class="count">{{ forloop.counter }}</a>
|
||||
{% if comment.user_url %}<a href="{{ comment.user_url }}">{{ comment.user_name }}</a>{% else %}{{ comment.user_name }}{% endif %} says...
|
||||
</h5>
|
||||
{{ comment.comment|urlizetrunc:"60"|markdown:"safe" }}
|
||||
<p class="date">Posted at {{ comment.submit_date|date:"P" }} on {{ comment.submit_date|date:"F j, Y" }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if object.allow_comments %}
|
||||
{% render_comment_form for object %}
|
||||
{% else %}
|
||||
<div id="comment_form">
|
||||
<h3>Comments are closed.</h3>
|
||||
<p>Comments have been close for this post.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post archive{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_list{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Post archive</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if is_paginated %}
|
||||
<p class="pagination">
|
||||
{% if has_next %}
|
||||
<a class="older" href="?page={{ next }}">Older</a>
|
||||
{% endif %}
|
||||
{% if has_next and has_previous %} | {% endif %}
|
||||
{% if has_previous %}
|
||||
<a class="newer" href="?page={{ previous }}">Newer</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
{% extends "blog/base_blog.html" %}
|
||||
|
||||
|
||||
{% block title %}Post search{% endblock %}
|
||||
{% block body_class %}{{ block.super }} post_search{% endblock %}
|
||||
|
||||
|
||||
{% block main-content_title %}
|
||||
<h2>Search</h2>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block main-content %}
|
||||
<form action="." method="get" id="post_search_form">
|
||||
<p>
|
||||
<input type="text" name="q" value="{{ search_term }}" id="search">
|
||||
<input type="submit" class="button" value="Search">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
{% if message %}
|
||||
<p class="message">{{ message }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if object_list %}
|
||||
<div class="post_list">
|
||||
{% for post in object_list %}
|
||||
<div>
|
||||
<h3 class="title"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h3>
|
||||
<p class="date">{{ post.publish|date:"Y F d" }}</p>
|
||||
<p class="tease">{{ post.tease }}</p>
|
||||
<p class="comments">{% if comment_count %}{{ comment_count }} comment{{ comment_count|pluralize }}{% endif %}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Loading…
Reference in New Issue