ArunRocks - Building a Hacker News Clone in Django - Part 2 (User Profiles and Registrations)

download ArunRocks - Building a Hacker News Clone in Django - Part 2 (User Profiles and Registrations)

of 10

Transcript of ArunRocks - Building a Hacker News Clone in Django - Part 2 (User Profiles and Registrations)

  • 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/)

    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/)

    It has been more than a week since the first part of this tutorialseries(/building-a-hacker-news-clone-in-django-part-1/) was posted and Ivebeen getting positive feedback from several channels. Ironically, it wasextremely popular on Hacker News(https://news.ycombinator.com/item?id=5784689). It was even translated intoChinese(http://www.oschina.net/translate/building-a-hacker-news-clone-in-django-part-1).

    To be sure, the objective was not to create a full featured clone of anywebsite. The real objective is to learn Django using a medium-sized projectthat utilises it to the fullest. Many tutorials fall short of bringing togethervarious parts of Django. Compared to a microframework like Flask (which isalso great, btw), Django comes with a lot of batteries included. If you areshort on time, this makes it ideal for completing an ambitious projectlike this.

    This tutorial would show you how to implement social features likesupporting user registration and profile pages. We will leverage Djangosclass based views(https://docs.djangoproject.com/en/dev/topics/class-based-views/) for buildingCRUD(http://en.wikipedia.org/wiki/Create,_read,_update_and_delete)functionality. There is a lot of ground to be covered this time.

    As before, there is a text description of the steps if you do not prefer to watchthe entire video. There is also a goodies pack(https://github.com/arocks/sr-goodies/archive/master.zip) with templates and other assets included, whichwould be required if you are following this tutorial.

    This video would be a continuation of the previous video(/building-a-hacker-news-clone-in-django-part-1/) and I recommend watching it. Click on theimage below to watch the screencast or scroll down to read the steps.

    (http://www.youtube.com/watch?v=NeYKGTSFF6I&hd=1)

    Enjoyed this tutorial? Then you should sign up for my upcoming bookBuilding 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

    BLOG(/ ARCH IVES / )ABOUT (H TTP :/ / ARUNROCKS .COM / ABOUT/ )

    A RU N RO CKS ( / )

    Arun Ravindran

  • are built andgraduallytacklesadvancedtopics liketesting,security,databasemigrationsand debugging.

    Step-by-

    step Instructions

    Here is the text version of the video for people who prefer to read. In part 1,we showed you how to create a private beta-like site to publish rumors aboutMan of Steel(http://www.imdb.com/title/tt0770828/).

    The outline of Part 2 of the screencast is:

    Better branding and templatesCustom login/logoutSociopath to actually social - django-registrationsSimple registrationUser Profiles

    Open the goodies pack

    So far, the appearance of the website looks a bit bland. Lets use some assetswhich are pre-designed for the tutorial.

    1. Download sr-goodies-master.zip(https://github.com/arocks/sr-goodies/archive/master.zip) to any convenient location. On Linux, youcan use the following commands to extract it to the /tmp directory.

    cd /tmpwget https://github.com/arocks/sr-goodies/archive/master.zipunzip master.zip

    Explore the extracted files in /tmp/sr-goodies-master

    2. Copy the entire static directory from the extracted files tosteelrumors/steelrumors. Also, overwrite the extracted sr-goodies-master/templates/base.html template intosteelrumors/steelrumors/templates/

  • cp -R /tmp/sr-goodies-master/static ~/proj/steelrumors/steelrumors/cp /tmp/sr-goodies-master/templates/base.html ~/proj/steelrumors/steelrumors/templates/

    Custom Login page

    1. Add to steelrumors/urls.py:

    url(r'^login/$', 'django.contrib.auth.views.login', { 'template_name': 'login.html'}, name="login"),url(r'^logout/$', 'django.contrib.auth.views.logout_then_login', name="logout"),

    2. Add the login/logout URL locations to steelrumors/settings.py:

    from django.core.urlresolvers import reverse_lazy

    LOGIN_URL=reverse_lazy('login')LOGIN_REDIRECT_URL = reverse_lazy('home')LOGOUT_URL=reverse_lazy('logout')

    3. Now copy login.html from the goodies pack to the templates directory:

    cp /tmp/sr-goodies-master/templates/login.html ~/proj/steelrumors/steelrumors/templates/

    Refresh your browser to view the newly styled pages.

    Using django-registrations

    We will be using the simple backend(https://django-registration.readthedocs.org/en/latest/simple-backend.html) of django-registrations(https://django-registration.readthedocs.org/en/latest/) since it iseasy to use and understand.

    1. Currently, the version of django registration on the the PythonPackage Index(https://pypi.python.org/pypi/django-registration)doesnt work well with Django 1.5. So we will use my forked versionusing pip:

    pip install git+git://github.com/arocks/django-registration-1.5.git

    Or if you dont have git installed, use:

    pip install https://github.com/arocks/django-registration-1.5/tarball/master

    2. Edit settings.py to add registration app to the end of INSTALLED_APPS

    'registration',)

    3. Run syncdb to create the registration models:

    ./manage.py syncdb

  • 4. We need to use the registration form template from goodies pack.Since, this is for the registration app we need to create a registrationdirectory under templates:

    mkdir ~/proj/steelrumors/steelrumors/templates/registration/cp /tmp/sr-goodies-master/templates/registration/registration_form.html ~/proj/steelrumors/steelrumors/templates/registration/

    5. Add to urls.py:

    url(r'^accounts/', include('registration.backends.simple.urls')),

    Visithttp://127.0.0.1:8000/accounts/register/(http://127.0.0.1:8000/accounts/register/)and create a new user. This will throw a Page not found error after auser is created.

    Create a users profile page

    1. Add UserProfile class and its signals to models.py:

    class UserProfile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.TextField(null=True)

    def __unicode__(self): return "%s's profile" % self.user

    def create_profile(sender, instance, created, **kwargs): if created: profile, created = UserProfile.objects.get_or_create(user=instance)

    # Signal while saving userfrom django.db.models.signals import post_savepost_save.connect(create_profile, sender=User)

    2. Run syncdb again to create the user profile model:

    ./manage.py syncdb

    3. Add these to admin.py of links app to replace/extend the default adminfor User:

  • from django.contrib.auth.admin import UserAdminfrom django.contrib.auth import get_user_model...class UserProfileInline(admin.StackedInline): model = UserProfile can_delete = False

    class UserProfileAdmin(UserAdmin): inlines=(UserProfileInline, )

    admin.site.unregister(get_user_model())admin.site.register(get_user_model(), UserProfileAdmin)

    Visit http://127.0.0.1:8000/admin/(http://127.0.0.1:8000/admin/) andopen any users details. The bio field should appear in the bottom.

    4. Add to views.py of links apps:

    from django.views.generic import ListView, DetailViewfrom django.contrib.auth import get_user_modelfrom .models import UserProfile....class UserProfileDetailView(DetailView): model = get_user_model() slug_field = "username" template_name = "user_detail.html"

    def get_object(self, queryset=None): user = super(UserProfileDetailView, self).get_object(queryset) UserProfile.objects.get_or_create(user=user) return user

    5. Copy user_detail.html from goodies to steelrumors/templates/:

    cp /tmp/sr-goodies-master/templates/user_detail.html \ ~/proj/steelrumors/steelrumors/templates/

    6. Lets add the urls which failed last time when we tried to create a user.Add to urls.py:

    from links.views import UserProfileDetailView...url(r'^users/(?P\w+)/$', UserProfileDetailView.as_view(), name="profile"),

    Now try to create a user and it should work. You should also see theprofile page for the newly created user, as well as other users.

    7. You probably dont want to enter these links by hand each time. Solets edit base.html by adding the lines with a plus sign + (omitting theplus sign) below:

  • {% if user.is_authenticated %} Logout | + {{ user.username }} {% else %} + Register |

    Refresh the browser to see the changes.

    Edit your profile details

    1. Add UserProfileEditView class to views.py in links app:

    from django.views.generic.edit import UpdateViewfrom .models import UserProfilefrom .forms import UserProfileFormfrom django.core.urlresolvers import reverse

    class UserProfileEditView(UpdateView): model = UserProfile form_class = UserProfileForm template_name = "edit_profile.html"

    def get_object(self, queryset=None): return UserProfile.objects.get_or_create(user=self.request.user)[0]

    def get_success_url(self): return reverse("profile", kwargs={'slug': self.request.user})

    2. Create links/forms.py:

    from django import formsfrom .models import UserProfile

    class UserProfileForm(forms.ModelForm): class Meta: model = UserProfile exclude = ("user")

    3. Add the profile edit view to urls.py. Protect it with an auth decorator toprevent unlogged users from seeing this view.

    from django.contrib.auth.decorators import login_required as authfrom links.views import UserProfileEditView...url(r'^edit_profile/$', auth(UserProfileEditView.as_view()), name="edit_profile"),

    4. Copy edit_profile.html from goodies to steelrumors/templates/:

    cp /tmp/sr-goodies-master/templates/edit_profile.html \ ~/proj/steelrumors/steelrumors

  • 5. Add the following lines to templates/user_detail before the final endblock:

    {% if object.username == user.username %}Edit my profile{% endif %}

    Now, visit your profile page and try to edit it.

    Easter Egg Fun

    Add the following lines to user_detail.html before the endblock line:

    {% if "zodcat" in object.userprofile.bio %}

    html { background: #EEE url("/static/img/zod.jpg");}

    {% endif %}

    Now mention zodcat to your bio. You have your easter egg!

    Final Comments

    We have a much better looking site at the end of this tutorial. While anyonecould register to the site, they will not be part of the staff. Hence, you cannotsubmit links through the admin interface. This will be addressed in thenext part.

    That concludes Part 2. Follow me on Twitter at@arocks(http://twitter.com/arocks/) to get updates about upcoming parts.

    Resources

    Full Source(https://github.com/arocks/steel-rumors/tree/episode2)on GithubGoodies pack(https://github.com/arocks/sr-goodies/archive/master.zip) on Github

  • Building a Hacker News clone inDjango - Part 3 (Commentsand CRUD)(http://arunrocks.com/building-a-hacker-news-clone-in-django-part-3/)

    Building a Hacker News clone inDjango - Part 1

    (http://arunrocks.com/building-a-hacker-news-clone-in-django-part-1/)

    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 affairscould be blamed on the ecelectic interests of your host, Arun Ravindran. Heloves programming in several languages especially Python. In his day job heworks as a Solution Manager at Unisys. Read more...(/about/)

    Posted on: Thu 06 June 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)

    Share on: Twitter(http://twitter.com/share?url=http://arunrocks.com/building-a-hacker-news-clone-in-django-part-2/),Facebook(http://www.facebook.com/sharer.php?u=http://arunrocks.com/building-a-hacker-news-clone-in-django-part-2/),Google+(https://plus.google.com/share?url=http://arunrocks.com/building-a-hacker-news-clone-in-django-part-2/)

    Comments

    8Comments ArunRocks Login

    SortbyOldest Share Favorite

    Don'tmissanyfutureposts!

    Subscribetoourmailinglist

    emailaddress

    Subscribe

  • Jointhediscussion

    Reply

    tony ayearagoThankslovingthistutorial.Lookingforwardtoseehowyouimplementthefrontendforvoting.

    1

    Reply

    jackson 10monthsagoIwasalsogettinganintegrityerrorwhenIaddedanewuseratstep6ofcreatingauser'sprofilepageabove.

    Icommentedoutthefollowinglinesinmodels.pyandIcouldcreateusers:

    #fromdjango.db.models.signalsimportpost_save

    #post_save.connect(create_profile,sender=User)

    Reply

    jackson 10monthsagoUnderedityourprofilestep3,Ihadtoadd'UserProfileEditView'totheendofthisline:

    fromlinks.viewsimportLinkListView,UserProfileDetailView,UserProfileEditView

    Reply

    CJMac 9monthsago

    seemore

    Hi,I'mrunningintothiserrorandhaven'tbeenabletosolveityet.Ioriginallyhadtofightwithafewfilesformixingtabsandspaces.NowthatIhavegotridofthaterror,Inowgetthiserror,ifanyonecouldpointmeintherightdirectionthatwouldbegreat.

    "

    Nomodulenamedforms

    RequestMethod:GET

    RequestURL:http://127.0.0.1:8000/

    DjangoVersion:1.5.2

    ExceptionType:ImportError

    Share

    Share

    Share

    Share

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

    MarsRoverinPythonandHaskell3commentsayearago

    AkkulThanksfordroppingby!IhavemovedtheL&Rorientationmappingbeforewhile(thatwasntsupposedtobeinthe

    RealtimeApplicationsandwillDjangoadapttoit?21comments7monthsago

    HAHAHAHAHAHAHAHHAHAHAAHHAHAHAHLastjobweusedMeteor.js,wereadthebook,andwentouttobuildthe

    DecodingGooglesFirstTweetinPython1commentayearago

    UnderstandingTestDrivenDevelopmentwithDjango5comments3monthsago

    ALSOONARUNROCKS

    Reply

    Reply

    ChrysCantonaOgwara 8monthsagohowdoiputprofilepictures

    Reply

    ArunRavindran 8monthsago

    Author ChrysCantonaOgwara

    Ithinkyoucancheckdjangogravatar2forthis.

    Reply

    muck 5monthsagothanksforthetutorial!FYI:i'musingdjango1.6.1andIwasgettinganimportError'nomodulenamedefaultsfound'whenItriedtocompletetheUsingDjangoRegistrationstep.So,ingoodies/registration/auth_urls.pyandregistration/backends/simple/urls.pyIchanged"fromdjango.conf.urls.defaultsimport*"to"fromdjango.conf.urlsimportpatterns,url,include"andthisworked.Apparently,fromdjango.conf.urls.defaultsimport*isnolongerinuseondjango1.6

    Reply

    ArunRavindran 5monthsagoAuthor muckThanksmuckforhighlightingthisproblemandprovidingasolution.IshallupdatetheregistrationappsothatitworksfineinDjango1.6.

    WHAT'STHIS?

    Share

    Share

    Share

    Share

    Share