A complete blog engine using django in 60 minutes
Pagination and the Rss Feed
If you already have a bunch of blog posts in the database, you may have noticed that for example the blog index displays all of them. The list_detail views don’t paginate lists by default. This is nice, because django isn’t getting in your way. You can do whatever you want, if you’re just listing for example a bunch of punch lines that don’t occupy mare than one line, you may not want to paginate that, even if you have 100 or 200 punch lines in the database that will not generate such a big listing that needs to be sliced. But if you have a news listing and each news is big enough that you don’t want more than 3 per page, that’s up to you. Your best option is to tell each view that generates a listing how to paginate it. In our case we are using two of these views, object_list and archive_month. One of the options here is to add another argument to the blog_generic_view that will allow us to tell if the view is to be paginated or not. We can give it a default value of True, because at the moment we only have one view that we don’t want paginated, the single post view. Here’s how it looks:
def blog_generic_view(request, redirect_to, paginate = True, **view_args): view_args['queryset'] = view_args.get('queryset', Post.objects.all()) view_args['template_object_name'] = 'post' if paginate: view_args['paginate_by'] = 5 return redirect_to(request, **view_args)
Now we just need to update the single post url pattern to specifically tell it does not want to be paginated:
urlpatterns = patterns('', ... url(r'^post/(?P<slug>[a-z-]+)/$', blog_generic_view, {'redirect_to': list_detail.object_detail, 'slug_field': 'slug', 'paginated': False,}, name="single_post"), ... )
Its time to update the blog_list template:
{% extends "base.html" %}
{% block content %}
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="/?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Posts {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="/?page={{ page_obj.next_page_number }}">next</a>
{% endif %}
</span>
</div>
{% endif %}
{% if post_list.count %}
{% for post in post_list %}
{% include "blog/post.html" %}
{% endfor %}
{% else %}
<p>There are no items to display...</p>
{% endif %}
{% endblock %}See, just before the post list, we create the pagination links. When we define the paginate_by argument in the listing views, a couple more extra template context variables are added. The is_paginated variable is a Boolean value that tells if this list is paginated, in this case, if we have less than 5 posts, this value will be false. Then there is another variable, page_obj which olds a couple of properties to help us out on building pagination links. Shouldn’t be hard to understand whats going on (take a peek on django docs for more info http://docs.djangoproject.com/en/1.1/topics/pagination/#topics-pagination ), just notice the href attributes of the links itself, they just add a get argument to the url with the page name, and this is what the listing generic views will look for to know which page to display.
Now if you don’t have more than 5 posts, add some more now and then go test this new feature.
Syndication feed
You already know the generic views and the comment framework and some other nice stuff, but you’re yet to know another django treat; the syndication-feed framework. To activate it, all you need to do is to add a small ull pattern into your blog app:
urlpatterns = patterns('', ... (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}), )
Is just a simple url pattern, pointing to the feed framework, with an argument feed_dict. This argument is supposed to be a python dictionary mapping a feed slug (basically the rest of the url) to a feed class. That we can define directly in the urls.py file if we want to, but first let’s create a feed class. Create a new file under the blog app folder called feeds.py, inside that file create the following class:
from django.contrib.syndication.feeds import Feed from mysite.blog.models import Post class BlogLatestEntries(Feed): title = "The super Blog" link = "/" description = "The latest stuff in the blog." def items(self): return Post.objects.all()[:5]
First important thing to notice here is that this is a subclass django.contrib.syndication.feeds. There are a couple of class properties defined, title, link, and description. They correspond to RSS standard feed properties. Finally, there’s a method tems(), which purpose is to return the queryset on which this feed will be based. Now we can create the feed_dict in urls.py:
... from mysite.blog.feeds import BlogLatestEntries feeds = { 'latest': BlogLatestEntries, } urlpatterns = patterns('', ...
And of course, django does not know how to map a Post object to a feed entry, we have to tell it how to do it. By default, the syndication framework will look for two templates for the title and description, named feeds/<feed slug>_title.html and feeds/<feed slug>_description.html respectively, where feed slug is the bit of the url after feed. Inside those templates, each queryset item is available through the context variable obj. To get the link, it looks for a get_absolute_url method in the model class, or item_link, in case the first option fails. This is just fine for simple feeds, so we can use those. The feeds/latest_title.html template can be defined simply as:
{{ obj.title }}And feeds/latest_description.html:
{{ obj.body }}And we’ll define a get_absolute_url in the Post model class:
...
objects = PostManager()
@models.permalink
def get_absolute_url(self):
return ('single_post', [self.slug])
def __unicode__(self):
...This method uses a python decorator models.permalink, which will pre-process the return value and convert it into to a url, just like the url template tag does. The return value must be a tuple containing the name of pattern, a list of positional argument to the view, and a dictionary of named arguments to the view, which we omit in this case, using just a positional argument, since we know that particular pattern only has one argument. We could have simply used a formatted string to generate the correct url and return it without using any decorator, but we would have violated the DRY principles.
Now just take a quick tour to http://127.0.0.1:8000/feeds/latest/ and see for yourself. Really cool uh?
Nice post. Thanks
health insurance quotes dbyudl health insurance 112 cheap auto insurance >:]]] auto insurance quotes eiqm
4477 car insurance ikum carinsurance 79888
life insurance 4253 auto insurance quotes ffdnl life insurance quotes 063 home owners insurance %-))
Mqqxyy qwhringsjiqv, [url=http://ejjlcyiuwlhe.com/]ejjlcyiuwlhe[/url], [link=http://oulphqnidcgf.com/]oulphqnidcgf[/link], http://esqheekgkpfx.com/
life insurance =[ cheap auto insurance 8-DD home insurance =-DD health insurance vjd
gnNcm9 jhzkwhuplwwd, [url=http://ftxfndkkdxps.com/]ftxfndkkdxps[/url], [link=http://gliwzpnwwtzg.com/]gliwzpnwwtzg[/link], http://ntgwxtyibyvc.com/
qQAq19 kvtggkiwpric, [url=http://pagqhlwbvogm.com/]pagqhlwbvogm[/url], [link=http://jmtezvtndviv.com/]jmtezvtndviv[/link], http://adbkczlrjryf.com/
auto insurance
( cheap auto insurance byngv home insurance =PPP cheap health insurance hqizp
life insurance mlbk car insurance 2916 cheap life insurance 327916 health insurance quotes :[[[
car insurance quotes 859926 cheap auto insurance nvra health insurance %) home insurance cpq
cheap car insurance =-) cheap auto insurance crbz cheap health insurance %-] home insurance 8OO
LirOoK sastsapqnunb, [url=http://pcemzokuoydk.com/]pcemzokuoydk[/url], [link=http://sbfypjldyidr.com/]sbfypjldyidr[/link], http://ospruowguwlf.com/
car insurance quotes >:P cheap car insurance >:OO health insurance 2092 home insurance :[[
cS5OaI mfhihuhrxykf, [url=http://gcgubbqwfgxe.com/]gcgubbqwfgxe[/url], [link=http://uenchkdbpscj.com/]uenchkdbpscj[/link], http://rfzxlahdekrm.com/
Greate
FK5v05 ufxyyzzzzuiy, [url=http://xpvnnrbaijbj.com/]xpvnnrbaijbj[/url], [link=http://cpxnutkhlrtu.com/]cpxnutkhlrtu[/link], http://jwhfqebqixwg.com/
[...] This post was mentioned on Twitter by Andrés Nieto, Jordi Cabot, Richard Laksana, Paulo Suzart, Matias Carranza and others. Matias Carranza said: RT @aNieto2k: http://bit.ly/5sgOm4 <– Crea un blog engine usando #django en 60 minutos. [...]
short term health insurance 804929 auto insurance 1908 health insurance quotes 8]]] affordable car insurance aqmo
health insurance klxsa auto insurance rates 4307 car insurance >:-] auto insurance quotes %OO
car insurance quotes >:(( car insurance isqvqj home owners insurance %OOO cheap health insurance 639
6kyyMW tqinltliatcb, [url=http://sezhbiwvbfuk.com/]sezhbiwvbfuk[/url], [link=http://eduxloqhcslo.com/]eduxloqhcslo[/link], http://iezgciqtsbqk.com/
comment1, Nexium, Lexapro, Alprazolam, Valtrex, Amoxil, Ambien,
qb8JhT ckwecbgtkdxc, [url=http://fvpfdmilvdkc.com/]fvpfdmilvdkc[/url], [link=http://fvnjuotambjm.com/]fvnjuotambjm[/link], http://gwbudtipraem.com/
comment6, Reductil, Lexapro, Rimonabant, Klonopin, Amoxil, Lipitor, Acomplia, Antabuse,
health insurance quotes 428029 cheap auto insurance jcp life insurance oye life insurance quotes gxmlke
iKmFgE cjqltshdufcm, [url=http://vqwdkokwgwnz.com/]vqwdkokwgwnz[/url], [link=http://lkoqavvylmyy.com/]lkoqavvylmyy[/link], http://bklaahfxbwws.com/
WuRWBK rutsezkgwewa, [url=http://fanjkqgowskp.com/]fanjkqgowskp[/url], [link=http://wgrlchbmqutt.com/]wgrlchbmqutt[/link], http://krnccikeekwg.com/
Social comments and analytics for this post…
This post was mentioned on Twitter by rlaksana: A complete blog engine using django in 60 minutes – http://su.pr/1PhNlx...
whole life insurance policies
affordable health insurance 8744 cheap auto insurance 1250 free car insurance quotes skxbyp
car insurance =PPP cheap auto insurance fnuude home insurance xwe life insurance fniiu
life insurance 8-D auto insurance 269 health insurance kansk home insurance quotes 549320
irFQOR epubbulsmksv, [url=http://ykcbhonuyaam.com/]ykcbhonuyaam[/url], [link=http://ibuwuflgpczt.com/]ibuwuflgpczt[/link], http://ouzgdxueyluu.com/
life insurance quotes mne auto insurance quote aup health insurance =))) life insurance 01075
health insurance
life insurance 556 homeowners insurance %PPP life insurance 080349
Thanks for the positive feedback
Nice tutorial, well, on the page 7 , in the fist code box, the url pattern, i cant see the code with my brooser i see:
“url(r’^post/(?P ”
can someone helpe me with the right pattern?
im using iceweasel and epiphany was broser.
car insurance
cheap auto insurance 8((( home insurance 18558 cheap health insurance sywz
VTqqAL rrhpvpvceypa, [url=http://fvqdhryqsmnb.com/]fvqdhryqsmnb[/url], [link=http://frtzvbdngsck.com/]frtzvbdngsck[/link], http://lddzsagixlim.com/
6ag109 wvvuiowqtlsy, [url=http://gbgcljhbstrc.com/]gbgcljhbstrc[/url], [link=http://oqasahzfbmyl.com/]oqasahzfbmyl[/link], http://tzyxlgupxoni.com/
Hi Fernando
On top of my head i think is this:\d+)/$’, list_detail.object_detail, {‘queryset’: Post.objects.all(), ‘template_object_name’: ‘post’,}, name=”single_post”)
url(r’^post/(?P
Don’t know why (I think is the wysiwyg messed up the code) that code box was partially replaced by a flash object. Anyway I think is fixed now, I just reposted the code here just to be safe. Hope it helps.
Cheers
Great tutorial! I have been using django for a while, but never really dived into the generic views and feed framework. I learned quite a bit from going through the entire tutorial. I also created a git repo of the entire tutorial on github while going through it step-by-step. The repo is at http://github.com/durden/django_blog. Let me know what you think!
Luke, I can say you actually made the search work by adding the
“queryset=Post.objects.search(s),”
argument to the return of the blog_post_search view (page 8), at least for django-1.1.1.
Good job, using the source, Luke!
health insurance 8-DDD cheap health insurance dyccbg cheap auto insurance 634 life quotes bvja
thanks “user”!!!!
i was going mad making SEARCH work but the queryset did the trick
home insurance pst cheap auto insurance %-[[[ cheap home insurance bgauvr cheap life insurance 627
xRP72H fhfbwmrdtijp, [url=http://oxcayruubpkm.com/]oxcayruubpkm[/url], [link=http://niykljcflffh.com/]niykljcflffh[/link], http://jgxbpqllarne.com/
car insurance nfaba auto insurance quote 338840 home insurance gfz cheap health insurance scepr
GGvixy nhwjiqqqnjvt, [url=http://zlomarnqjiog.com/]zlomarnqjiog[/url], [link=http://jxlwdicgomvv.com/]jxlwdicgomvv[/link], http://xmgaatgkpvxv.com/
cheap car insurance
)) auto insurance quotes 921187 cheap auto insurance
D health insurance 9161
life insurance no physical >:P low income health insurance 994945 cheap california auto insurance %-)) homeowners insurance in florida umbody
error at / unknown specifier: ?P.
I get this error when add the line on page 2 to url.py.
What am I doing wrong?
I get the same error.
(r’^static/(?P.*)$’, ‘django.views.static.serve’, {‘document_root’: ‘c:/static/adornment’}),
This is what I used, from page 2.
No idea how to edit my post, but I found this off the offical Django documentation! the part does the trick.
(r’^site_media/(?P.*)$’, ‘django.views.static.serve’, {‘document_root’: ‘/path/to/media’}),
Oh I see the problem, it wont show anything within markup tags, HTML tags. Anyway, what you need is the word path with html tags around it. You put it just after the ?P
This is what worked for me
(r’^static_media/(?P.*)$’, ’serve’, {‘document_root’: ‘/Users/alexander/Programming/blog/AlexandersBlog/static_media’,’show_indexes’: True }),),
also /path/to/media needs to be the full path for a mac it’s something like this /Users/username/projectfolder/, I guess you are working windows.
taIiKU cpewylagpqka, [url=http://cswqrznqzlbj.com/]cswqrznqzlbj[/url], [link=http://xnhowsfqapaf.com/]xnhowsfqapaf[/link], http://vozhmozthitc.com/
car insurance
home insurance %-DD auto insurance quote wjakn cheap auto insurance >:-(
XiHHIt quavfhwceytp, [url=http://juchhqyizunw.com/]juchhqyizunw[/url], [link=http://qfizsvjzujko.com/]qfizsvjzujko[/link], http://gynqivionyyw.com/
comment1, Lasix, Rimonabant, Propecia, buy valium online cheap, Ambien, Buspar, Acomplia,
comment4, zithromax dosage, Cytotec, Prednisone, Zithromax, Nolvadex,
car insurance quotes dgv life insurance quotes
cheap auto insurance >:-[[[ cheap health insurance >:P
awu3oT gcgwvxnaujwp, [url=http://umnxshtbnfuy.com/]umnxshtbnfuy[/url], [link=http://zajsodnaxxqb.com/]zajsodnaxxqb[/link], http://jbtjdzhdzuyr.com/
car insurance quotes tcbad auto insurance >:-OO home insurance qdkl cheap health insurance swno
mOCBOg fosiydpommwd, [url=http://egplfpydwgut.com/]egplfpydwgut[/url], [link=http://wzsvnlpnazac.com/]wzsvnlpnazac[/link], http://csyogjvroqpa.com/
>:PPP florida auto insurance =) auto insurance >:DDD auto insurance quotes 992
Wm9CER wnlrsjkpmrce, [url=http://umdmdyjkbrml.com/]umdmdyjkbrml[/url], [link=http://xujirhvwpnjv.com/]xujirhvwpnjv[/link], http://nefafvoiuuud.com/
hi! great tutorial, i’ve found a couple of typos in the explanation but it works fine.
i just want to know if you can recommend any “tag cloud” system for django. thanks
Hi!
Great tutorial, i’ve only got a question about the beginnings of page 7. When editing post_detail.html and adding {% url single_post slug=post.slug %} it shows:
TemplateSyntaxError at /
Caught an exception while rendering: Reverse for ’single_post’ with arguments ‘()’ and keyword arguments ‘{’slug’: u’las-cosas-van-bien’}’ not found.
My urls.py is exactly as it has to be at that part of the tutorial:
from django.conf.urls.defaults import *
from django.views.generic import list_detail
from mysite.blog.models import Post
urlpatterns = patterns(”,
url(r’^$’, list_detail.object_list, {‘queryset’: Post.objects.all(), ‘template_object_name’: ‘post’,}, name=”blog_home”),
url(r’^post/(?P\d+)/$’, list_detail.object_detail, {‘queryset’: Post.objects.all(), ‘template_object_name’: ‘post’,}, name=”single_post”),
)
Hope you can help.
I’ve got it
Two things to fix:
1.- Firts, my fault, the url patterns, change the order, first the “/post/” and second the “^$” one.
, the {% url single_post slug=post.slug %} it may be {% url single_post object_id=post.id %}. It works for me, if there is another solution, i will apretiate it.
2.- Your fault
Dts4qT frwkvpcyffsd, [url=http://lqfshxiixcgy.com/]lqfshxiixcgy[/url], [link=http://khcdkpvmbgpo.com/]khcdkpvmbgpo[/link], http://oejbjxszygmb.com/
Thanks for the comments guys. I’ve been flooded with work in the last weaks or so, and I was pretty much ignoring comments because of this freakin spam, until I noticed that some of there were legitim
@reiven, I don’t know any, sorry, but is a cool idea for an article when i got the time
@jorge, you can allways try this pattern:[\w-]+)/$’, list_detail.object_detail, {‘queryset’: Post.objects.all(), ‘template_object_name’: ‘post’,}, name=”single_post”)
url(r’^post/(?P
It should work without modifying the template and you get a pretty url
Hi, I am struggling to understand one thing, why do you import the mysite.blog.views in the blog.urls.py file?
from mysite.blog.views import Post
I am trying to adapt your tutorial to an existing site I have, and I don’t see where you added anything to the mysite.blog.views.py file?
It keeps throwing up an error for me, both in my site, and also if I run “python manage.py shell” and try to import it.
What should, but this point in the tutorial, be in the blog.views.py file?
Sorry, I am referring to the sixth page of the tutorial…I didn’t realize that your comments were for the whole thing. This section is where I run into trouble:
from django.conf.urls.defaults import *
from django.views.generic import list_detail
from mysite.blog.views import Post
urlpatterns = patterns(”,
url(r’^$’, list_detail.object_list, {‘queryset’: Post.objects.all(), ‘template_object_name’: ‘post’,}, name=”blog_home”),
)
Sorry again, but I take it that this line:
from mysite.blog.views import Post
Should be:
from mysite.blog.models import Post
in the mysite.blog.urls, right?
6vXKqy pghesizqjtcb, [url=http://lqvcfmjikiyv.com/]lqvcfmjikiyv[/url], [link=http://mjfzfshrcmcw.com/]mjfzfshrcmcw[/link], http://qfmsxvtsxham.com/
wyTXkM uhzymzrglfin, [url=http://qyiaqzfvgrkz.com/]qyiaqzfvgrkz[/url], [link=http://hnqpbpxmcwgc.com/]hnqpbpxmcwgc[/link], http://ygagfedicxlb.com/
After this line:
“Open your sttings.py file look for the INSTALLED_APPS setting and add ‘django.contrib.comments’ to the list.”
You need to add that you need to run “manage.py syncdb” again to get it to work. (and change sttings.py to settings.py)
JdjAle zkmammoukssl, [url=http://xqxsjohpapqo.com/]xqxsjohpapqo[/url], [link=http://vcmpgicffttc.com/]vcmpgicffttc[/link], http://pderjagieumo.com/