Sie sind auf Seite 1von 12

Building a Hacker News clone in Django -

Part 1(http://arunrocks.com/building-a-hacker-
news-clone-in-django-part-1/)
You are reading a post from a four-part tutorial series
Part 1(/building-a-hacker-news-clone-in-django-part-1/) Part 2(/building-a-hacker-news-clone-in-django-part-2/)
Part 3(/building-a-hacker-news-clone-in-django-part-3/) Part 4(/building-a-hacker-news-clone-in-django-part-4/)
There is no better way to learn something than to watch someone else do it .
So, if you have been waiting to go beyond the basics in Django, you have
come to the right place.
In this video tutorial series, I would take you through building a social news
site called Steel Rumors from scratch in Django 1.5. In case you dont like
videos and prefer to read the steps, you can find them here too.
Even though we will start from the basics, if you are an absolute beginner to
Django, I would suggest reading the
tutorial(https://docs.djangoproject.com/en/dev/intro/tutorial01/) or my
previous screencast on building a blog in
30 mins(http://www.youtube.com/watch?v=srHZoj3ASmk)
The completed site would support user signups, link submissions,
comments, voting and a cool ranking algorithm. My approach would be to
use as many builtin Django features as possible and use external apps only
when absolutely necessary.
Check out a [demo of Steel Rumors][demo] yourself.
Click on the image below to watch the screencast or scroll down to read
the steps.
BLOG( / ARCHI VE S/ )
ABOUT( HTTP: / / ARUNROCKS. COM/ ABOUT/ )
A RU N RO CKS ( / )
Arun Ravindran
1
(http://www.youtube.com/watch?v=ST9d7qevCVo&hd=1)
If you liked this tutorial, then you should sign up for my upcoming book
Building a Social News Site in Django(https://leanpub.com/social-news-
site-in-django). It tries to explain in a learn-from-a-friend style how websites
are built and gradually tackles advanced topics like database migrations
and debugging.
Step-by-step Instructions
Here is the text version of the video for people who prefer to read. We are
going to create a social news site similar to Hacker
News(https://news.ycombinator.com/) or Reddit(http://www.reddit.com/). It
will be called Steel Rumors and would be a place to share and vote some
interesting rumors about Man of
Steel(http://www.imdb.com/title/tt0770828/).
The outline of Part 1 of the screencast is:
Objective
VirtualEnv - Start from Scratch!
Model Managers - Dream Job #78
Basic Template
Generic Views - ListView and DetailView
Pagination - For free!
Setup Virtual Environment
1. We will create a virtual development environment using
virtualenv(http://pypi.python.org/pypi/virtualenv) and
virtualenvwrapper(https://bitbucket.org/dhellmann/virtualenvwrapper/).
Make sure you have installed them first:
mkvirtualenv djangorocks
I use an Ubuntu variant called Xubuntu in my screencast. But you
should be able to replicate these steps in other OSes with
minimal changes.
2. Install Django (make sure you already have pip(http://www.pip-
installer.org/en/latest/) installed)
pip install Django==1.5
You can also use Django 1.5.1. The latest Django version may or may
not work with our code, hence it is better to specify a version to follow
this tutorial.
Create Project and Apps
1. Create a project called steelrumors:
cd ~/proj
django-admin.py startproject steelrumors
cd steelrumors
chmod +x manage.py
2. Open steelrumors/settings.py in your favourite editor. Locate and
change the following lines (changes in bold):
1. ENGINE: django.db.backends.sqlite3
2. NAME: database.db,
3. At the end of INSTALLED_APPS = ( django.contrib.admin,
3. Next, change steelrumors/urls.py by uncommenting the following lines:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
)
4. Sync to create admin objects and enter the admin details:
./manage.py syncdb
5. Open a new tab or a new terminal and keep a server instance running
(dont forget to issue workon djangorocks in this terminal):
./manage.py runserver
6. Visit the admin page (typically at
http://127.0.0.1:8000/admin/(http://127.0.0.1:8000/admin/)) and login.
7. Create links app:
./manage.py startapp links
8. Enter the following two model classes into links/models.py:
from django.db import models
from django.contrib.auth.models import User
class Link(models.Model):
title = models.CharField("Headline", max_length=100)
submitter = models.ForeignKey(User)
submitted_on = models.DateTimeField(auto_now_add=True)
rank_score = models.FloatField(default=0.0)
url = models.URLField("URL", max_length=250, blank=True)
description = models.TextField(blank=True)
def __unicode__(self):
return self.title
class Vote(models.Model):
voter = models.ForeignKey(User)
link = models.ForeignKey(Link)
def __unicode__(self):
return "%s upvoted %s" % (self.voter.username, self.link.title)
9. Create the corresponding admin classes. Enter the following into
links/admin.py:
from django.contrib import admin
from .models import Link, Vote
class LinkAdmin(admin.ModelAdmin): pass
admin.site.register(Link, LinkAdmin)
class VoteAdmin(admin.ModelAdmin): pass
admin.site.register(Vote, VoteAdmin)
10. Enter the following into links/views.py:
from django.views.generic import ListView
from .models import Link, Vote
class LinkListView(ListView):
model = Link
11. Insert following lines into steelrumor/urls.py:
from links.views import LinkListView
...
urlpatterns = patterns('',
url(r'^$', LinkListView.as_view(), name='home'),
12. Create a new templates directory and enter the following at
steelrumors/templates/links/link_list.html:
<ol>
{% for link in object_list %}
<li>
<a href="{{ link.url }}">
<b>{{ link.title }}</b>
</a>
</li>
{% endfor %}
</ol>
13. Edit settings.py to add our two apps to the end of INSTALLED_APPS = (
'links',
'steelrumors',
)
14. Sync to create link objects:
./manage.py syncdb
Visit http://127.0.0.1:8000/admin/ and add a couple of Link objects.
Now if you open http://127.0.0.1:8000/ you should see the added Links
Add Branding
1. Create a common base template at steelrumors/templates/base.html:
<html>
<body>
<h1>Steel Rumors</h1>
{% block content %}
{% endblock %}
</body>
</html>
2. Modify steelrumors/templates/links/link_list.html and surround
previous code with this:
{% extends "base.html" %}
{% block content %}
...
{% endblock %}
VoteCount Model Manager
1. We need a count of votes within our generic ListView. Add these to
links/models.py:
from django.db.models import Count
class LinkVoteCountManager(models.Manager):
def get_query_set(self):
return super(LinkVoteCountManager,
self).get_query_set().annotate(
votes=Count('vote')).order_by('-votes')
2. Insert these two lines into the Link class in links/models.py:
class Link(models.Model):
...
with_votes = LinkVoteCountManager()
objects = models.Manager() #default manager
3. Edit links/views.py and insert these two lines into the LinkListView class:
class LinkListView(ListView):
...
queryset = Link.with_votes.all()
paginate_by = 3
Crazy Fun
You can add 100 votes to random headlines using the following lines in the
django shell:
$ ./manage.py shell
>>> from links.models import Link, Vote
>>> from django.contrib.auth.models import User
>>> a = User.objects.all()[0]
>>> for i in xrange(100): Vote(link=Link.objects.order_by('?')
[0],voter=a).save()
Now visit http://127.0.0.1:8000/admin/ to find lots of Votes objects.
Final Comments
In case, you are wondering if this version of the site would be useful, I would
say that it works well for a private beta version. Any new user would have to
be added by the admin interface manually. They must be of the staff kind if
they have to login via the admin interface. Staff can vote by manually
creating Vote objects.
The public facing part of the site can still show the top rumors based the
votes received by the staff. Based on how well designed the templates are,
this version could be also used to get feedback about the sites design
and branding.
That concludes Part 1. Follow me on Twitter at
@arocks(http://twitter.com/arocks/) to get updates about the following parts.
EDIT: Check out Part 2(/building-a-hacker-news-clone-in-django-part-2/)!
Resources
Full Source(https://github.com/arocks/steel-rumors/tree/episode1) on
Github (repository has changed!)
1. This became very controversial. Most people learn best by doing it
themselves. But they need to read/hear/see it first from someone. I am
actually a self-taught programmer. I learnt most of programming from
books and trying it myself.
Learning by doing is certainly the best way to learn. But among source
of learning, watching an expert is probably the best.
Arun Ravindran(http://arunrocks.com)
Hi! Welcome to ArunRocks, an odd collection of writeups on programming,
travel, gadgets and practically anything under the sun. This state of affairs
could be blamed on the ecelectic interests of your host, Arun Ravindran. He
loves programming in several languages especially Python. In his day job he
works as a Solution Manager at Unisys. Read more...(/about/)
Posted on: Wed 29 May 2013
Tagged: screencast(http://arunrocks.com/tag/screencast.html) /
django(http://arunrocks.com/tag/django.html) /
python(http://arunrocks.com/tag/python.html) /
technical(http://arunrocks.com/tag/technical.html) /
tutorial(http://arunrocks.com/tag/tutorial.html) /
steelrumors(http://arunrocks.com/tag/steelrumors.html)
Don'tmissanyfutureposts!
Subscribetoourmailinglist
emailaddress
Subscribe
Building a Hacker News clone in
Django - Part 2 (User Profiles
and Registrations)
(http://arunrocks.com/building-a-
hacker-news-clone-in-django-part-2/)
Easy and Practical Web scraping
in Python
(http://arunrocks.com/easy-
practical-web-scraping-in-python/)
Share on: Twitter(http://twitter.com/share?
url=http://arunrocks.com/building-a-hacker-news-clone-in-django-part-1/),
Facebook(http://www.facebook.com/sharer.php?
u=http://arunrocks.com/building-a-hacker-news-clone-in-django-part-1/),
Google+(https://plus.google.com/share?url=http://arunrocks.com/building-a-
hacker-news-clone-in-django-part-1/)
Comments
33Comments ArunRocks Login
SortbyOldest Share
Jointhediscussion
Reply
JonHearty ayearago
Thanks,Arun!Watchingyour'Buildingablogin30minutes'
videoonYouTubewasactuallyadefiningmomentformewhenit
cametolearningPythonandDjangowithoutitIdon'tknowifI
wouldeverhavecomeasfarasIhave.I'mactuallyworkingon
buildingsomethingverysimilartothisrightnow,soI'mexcitedto
watchthevideoandlearnsomethings!

3
Reply
ArunRavindran ayearago Author JonHearty
Gladtohearthatmyvideoshelpedyou.Hopetocreate
moreofthemandmakeDjangomoreaccessible.

1
Reply
KylePennell 9monthsago ArunRavindran
whynotputthisonUdemyandchargeforit?(I
workthere)

Reply
MakeEduFree
4monthsago
KylePennell
Whydon'tyoueffoffandmakeeducation
free?

Reply
zdys ayearago
Loveit.

2
Favorite
Share
Share
Share
Share
Share

Reply
dbg ayearago
thisiscool.thanksforposting.

1
Reply
Adi ayearago
wonderful,anydemo?

2
Reply
ArunRavindran ayearago Author Adi
Notyet.Shalltrytoputoneupnexttime!

Reply
scrummyin ayearago
SorryIhatetobepicky,butitthrewmeofftoseeXubuntuas
XUbuntu.ImaybewrongbutIhaveneverseenitthatway.

Reply
ArunRavindran ayearago Author scrummyin
Noproblem.Ihavefixedit.

1
Reply
PiotrMigdal ayearago
Nice,butthetextinstruction(whichIread,asIpreferreadingto
watching)missesafewsteps:
steelrumor/serrings.py
put
'links'and'steelrumors'inINSTALLED_APPS
steelrumor/urls.py
putline
fromlinks.viewsimportLinkListView

1
Reply
liuzhiyu ayearago PiotrMigdal
yes,Youareright,authormissthesesteps.

Reply
liuzhiyu ayearago PiotrMigdal
NameError:name'LinkVoteCountManager'isnotdefined.
Amimissanotherhiddensteps?

ArunRavindran ayearago Author PiotrMigdal


Thanksalotforpointingthisout.Ihaveaddedtheseinmy
post.
Share
Share
Share
Share
Share
Share
Share
Share
Reply
Reply
PiotrMigdal ayearago ArunRavindran
BTW:ThanksforpostingcodeonGitHub.
OtherwiseIwouldn'tfindwhatwaswrongwithmy
code.

Reply
liuzhiyu ayearago
NameError:name'LinkVoteCountManager'isnotdefined.
Igotthiswhenirun'./manage.pysyncdb',iknowknowwhy......

Reply
ArunRavindran ayearago Author liuzhiyu
Itwouldbehardtodebugwithoutseeingyourcode.Could
youcompareyourcodewithmycodeongithub?

Reply
liuzhiyu ayearago ArunRavindran
thankyou!

Reply
zkc ayearago liuzhiyu
YouneedtoputclassLinkVoteCountManagerdefinition
beforeclassLinkdefinition.

1
Reply
__future__ ayearago
Fantasticvideo!Lookingforwardtothefollowup...

1
Reply
matt ayearago
Thanksforthisgreatlecture.I'mcurioustoknowwhat'sthecolor
schemeyou'reusinginyourshell?
Thanks

1
Reply
ArunRavindran ayearago Author matt
IusethezenandartthemeforEmacs24.
EDIT:Youmeanttheterminalcolorscheme?Iusethe
defaultterminalcolorschemefromXubuntu.

Chrislawlor ayearago
Greattutorialsofar,thankyou!Ipersonallylearnbestby
followingthrougha'real'projectlikethis(whichiswhyIloved
Share
Share
Share
Share
Share
Share
Share
Share
Share
Reply
'PracticalDjangoProjects'somuch).
I'msurprisedyou'renotcapturingthedatetimeintheVotemodel.I
wouldthinkthatinformationwouldbeneededfortheranking
algorithm.

1
Reply
ArunRavindran ayearago Author Chrislawlor
Iamgladthatyouliketheapproach.Mostranking
algorithmsdon'tusethevotingtimestamps,probably
becauseitmightinvolvealotofcomputation.The
algorithmIwouldusewouldbesimplisticbuttypicalof
mostsocialsites.

1
Reply
RoaldD ayearago
Hey,Ithinkthe
>"Thereisnobetterwaytolearnsomethingthantowatch
someoneelsedoit."
partsoundslame,becauseobviouslythebestwaytolearntodo
somethingistodoit.
Greatstuff,bytheway.

Reply
Josh ayearago
Thankyou,beenlookingforsomethinglikethisforawhile!An
actualyprojecttopracticethethingsi'velearnt.Lookingforwardto
workingthroughthetutorialsandhopingsolearnasmuchas
possible!

Reply
CJMac 10monthsago
Hi,
First,thanksforthistutorial.
correctedmysillyerror.

Reply
Vladdy 7monthsago
Irunthefollwongcode:
>>>fromlinks.modelsimportLink
>>>foriinxrange(100):Vote(link=Link.objects.order_by('?')
[0],voter=a).save()
andgetthefollowingerror:
NameError:name'Vote'isnotdefined

Share
Share
Share
Share
Share
Share
Home(/) Feed(http://arunrocks.com/blog/feed/atom.xml) @arocks(http://twitter.com/arocks)

Reply
ArunRavindran 7monthsago Author Vladdy
Goodpoint.Inthefirstline,justaddVoteaswelltobe
imported.Shallupdatetheposttoo.

Reply
Vladdy 7monthsago ArunRavindran
Thankyousomuch.

Reply
Vladdy 7monthsago ArunRavindran
"voter=a"causedmesomeproblems.Isubstitutedit
with:
>>>user=User.objects.all()[0]
>>>foriinxrange(100):
...Vote(link=Link.objects.order_by('?')
[0],voter=user).save()
or
>>>foriinxrange(100):
...Vote(link=Link.objects.order_by('?')
[0],voter=User.objects.order_by('?')[0]).save()

Reply
8indaas 6monthsago
GreatArun!Thankyouverymuch.HowaboutTDD?Canyou
pleasemakeonethatshowsTDDbaseddevelopment?Thankyou
much

Reply
HiAron 4monthsago
YourockarunThanks!!.

Share
Share
Share
Share
Share