Sunday, March 22, 2015

Chapter 12 - User Authentication with Django Registration Redux

A couple notes for this chapter. In 12.1, make sure you are updating the correct urls.py file. There are two - one is: tango_with_django_project/tango_with_django_project/urls.py, while the other is in tango_with_django_project/rango/urls.py.

You want to update the first one with (r'^accounts/', include('registration.backends.simple.urls')),


In 12.3.6 you are asked to update the base.html template to account for the new links shown on the page http://127.0.0.1:8000/accounts/ (shown above). Don't panic if you see a weird looking 404 error page. Just look at the links listed and see why it makes sense that the tutorial is asking you to replace 'register' with 'registration_register', and 'login' with 'auth_login', etc.

Also important to read this sentence: Notice that for the logout, we have included a ?next=/rango/. This is so when the user logs out, it will redirect them to the index page of rango. If we exclude it, then they will be directed to the log out page (but that would not be very nice). 

The sentence refers to this direction: 
  • logout to point to <a href="{% url 'auth_logout' %}?next=/rango/">
In the future add "?next=<link path here>" to the end of a link if you want to redirect somewhere else.

However, to redirect a user to a custom page after a password has been changed, create a file called password_change_done.html and save it in templates/registration. See this documentation page for more details. You can base it off your base.html template and make it something like:

{% extends "rango/base.html" %}

{% block body_block %}
<h1>Password Changed</h1>
        <p>Good news! Your password has been changed.</p>
{% endblock %}

At first, I attempted to achieve this by adding a function in views.py that redirected to a template file in the regular templates/rango folder. The correct way is create a custom password_change_done.html file and save it in the registration template folder so that it shows you that page instead of the default page shown here:

This is a problematic page. Sure, it tells you that your password change was successful, but what if, after changing my password, I want to continue to browse the site? There's no link to the homepage. Clicking on "home" takes you to an admin login page, so if you're not an administrator, you've reached a dead end. It makes much more sense to direct the user to a custom page that tells the user that his/her password has been changed successfully, along with a link to the homepage.

This took me a long time to figure out, but I'm glad I managed to cobble together a solution. Phew. Onto the next chapter...

Wednesday, March 18, 2015

Chapter 11 - Cookies and Sessions

Chapter 11 is all about cookies. Unfortunately, not of the edible kind. I just spent 5 minutes pointlessly looking for the phrase ">>>> TEST COOKIE WORKED!" on the registration page, when in fact, it's supposed to print in your console window. Oops. Don't make the same mistake I did. Read the directions closely.

Note to self: stuff is not printed to the rendered HTML. It is printed in the console. It's like a private message to yourself, allowing you to test new features!

Also, if you want to implement a grammatically correct site counter ("you have visited this site __ time(s)") without the (s), put this in your about.html file:

    {% if visits > 1 %}    
        <p>You have visited this site {{ visits }} times.</p>
    {% else %}
        <p>You have visited this site {{ visits }} time.</p>
    {% endif %}

An if/else statement to the rescue! Yay, grammar!

Thursday, March 12, 2015

Ch. 9 User Authentication

If you are tempted to change your urls.py to match the snippet provided in this chapter, don't do it!

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^about/$', views.about, name='about'),
    url(r'^category/(?P<category_name_slug>\w+)$', views.category, name='category'),
    url(r'^add_category/$', views.add_category, name='add_category'),
    url(r'^category/(?P<category_name_slug>\w+)/add_page/$', views.add_page, name='add_page'),
    url(r'^register/$', views.register, name='register'),
    url(r'^login/$', views.user_login, name='login'),
    )

I am struggling with regular expressions, but I kind of hacked my way through chapter 8 and got the forms to work. In this chapter, however, I noticed that

url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),

changed to:

url(r'^category/(?P<category_name_slug>\w+)$', views.category, name='category')

do not change it! Leave it as url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category') or your application will complain.

Sunday, March 1, 2015

6.9 Exercises - How to Resolve an IntegrityError

One of the exercises in 6.9 is:

Update your population script so that the Python category has 128 views and 64 likes, the Django category has 64 views and 32 likes, and the Other Frameworks category has 32 views and 16 likes.

I kept getting a long error that ended with:
django.db.utils.IntegrityError: column name is not unique

This response on StackOverflow helped a lot. The key is that in models.py, the Category name is set to unique=True, so since a category with name Python already existed in the database (and thus was not unique), we were not able to update it with views and likes. 

After migrating the changes to models.py, and before running populate_rango.py, go into the admin page, delete the three categories. Alternatively this thread taught me that I could also delete the db.sqlite3 file and then run this command in terminal: python manage.py syncdb

Then create the superuser again, apply migrations and run populate_rango.py. You should now see views and likes updated in each category. Success! (This also comes in handy in the next chapter, when you create slugs).

Chapter 6 - Models and Databases - populate_rango.py

In the text for populate_rango.py, make sure to remove the indents in the add_page function:

def add_page(cat, title, url, views=0):
    p = Page.objects.get_or_create(category=cat, title=title)[0]
        p.url=url
        p.views=views
        p.save()
    return p

p.url, p.views and p.save() should not be indented here.

Chapter 6 - Models and Databases

Ooh, models. Unfortunately we're not talking about extremely attractive people. According to the official Django tutorial, A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.

Well, ok, then.

The coolest thing about this chapter is creating your superuser. Woohoo! Kind of makes you feel like you're on your way to becoming a superhero.

Note to self, this seemed important for future use:

Thought I'd put it here because it seems like something I will forget later.

Another thing about this chapter to note: 
If it bothers you (like it bothered me) that the admin interface slaps an S on Category to make it Categorys instead of Categories, the tutorial helpfully points out that you can add a nested Meta class within your Category class in models.py, to alert the admin to a special plural spelling. 

It's simply a matter of inserting this right under the __unicode__ function in your Category class:

class Meta:
    verbose_name_plural = "Categories"

...and voila. Your admin is now grammatically correct. Yay!

Chapter 5 - Templates

Hit a roadblock today where I accidentally moved all the files to the wrong folder, so I had to start chapter 4 over from scratch.

The instructions say: In your Django project’s directory (e.g. <workspace>/tango_with_django_project/), create a new directory called templates.

<workspace> is referring to code/tango_with_django_project

(NOT code/tango_with_django_project/tango_with_django_project).

So the structure of your project should look like this:



Lesson learned. Add as many print statements to settings.py as needed.
I added print "base directory is  " + BASE_DIR to mine, so that I could spot "base directory is" quickly among all the mumbo jumbo in the command line.

In which this English major gets with the program.

Greetings, Earthlings.

I created this blog for the non-computer-science people who are currently learning how to code.

I studied English in college. Unlike most of my peers, I didn't have any plans to become a lawyer or teacher. I just wanted to get paid to read and write. After graduation, I moved to New York and managed to find a job that would let me do just that. Sounds like a happy ending, no? Not quite.

About a year and a half ago, I was laid off from my copywriting gig at what I thought was my dream job/company. I found another job in less than a month, but it awakened a formerly dormant part of my mind that grew and grew until it became a looming question: Wasn't it time I took control of my future?

Since I've always wondered what makes the Internet so magically addictive, I decided to learn how to program. Thanks to the plethora of online courses out there (most of them free!) it's easy for anyone with a laptop and an Internet connection to get started.

Python was my first introduction to the world of programming. Coursera offers a series of great Rice University courses: Intro to Interactive Programming in Python, Principles of Computing and Algorithmic Thinking. Warning: the third course is really challenging! But it's definitely worth trying...even if it makes you want to bang your head against the wall at times.

After that was over, I signed up for a Udemy course and learned some Javascript and PHP. That's when I really began to appreciate Python. It just makes more sense to me than other languages.

I created this blog to document my attempt to learn how to recreate Eat Decisive using Django and deploy it on Heroku. I am using this Django tutorial to get started.

Throughout my journey, I've read and will continue to read countless tutorials and Stack Overflow answers that have helped me immensely. Some of the tutorials I came across were written for people who were more experienced than little ol' me. It was frustrating at times, kind of like when you look a word up in the dictionary and the definition contains another word you don't know. With that in mind, some of my blog posts will be way too basic for many people. But those same basic posts will probably help other people who are in the same boat as me. So with that latter group in mind, I will try my best to share whatever information I acquire along the way, without assuming much prior knowledge.

Join me as I navigate the world of programming with a side of gifs and puns (I can't ignore my inner humanities major too much). Lots of fun times ahead.