Django & Python Adventure Part 6

Today I am going to focus on incorporating JQuery into Django. If you’re following along this is material covered in chapter 6 of Ayman Hourieh’s “Django 1.0 Web Site Development”. The book was published in March 2009, so this will be an interesting test of what’s changed in JQuery in 21 months. It was common practice back then to download a copy of JQuery, but, today I believe utilizing CDNs (Content Delivery Network) is the preferred method.

The big players run these CDNs:
• Microsoft: http://www.asp.net/ajaxlibrary/cdn.ashx
• Google: http://code.google.com/apis/libraries/
• JQuery: http://code.jquery.com/

As an interesting aside, some developers worry about their applications being unable to connect to the CDN 100% of the time. If you want to read more on this, read this blog about getting around it:

http://code-inside.de/blog-in/2011/02/06/howto-jquery-hosted-cdn-version-local-fallback/

One final note, it’s best to use the .min version of whatever JQuery as it has been “minified” to work faster for you application.

We only want to reference this once, so we’ll drop it in the Master Page base.html:

The first thing I want to implement is AJAX-enabled search functionality on the bookmarks. The book suggests the best practice of writing the search form without AJAX (so it should work if the AJAX fails) and then add on the AJAX functionality. This is called “Progressive Enhancement” and it simply means we try not to leave anyone out of the fun.

First: bookmarks/forms.py:

Second: bookmarks/views.py
Notice the search is already implemented in Django. We’re calling it with Bookmark.objects.filter(). When we passit arguments, they must be in the format: field__operator. For a .Net programmer I still find the double underscore a little odd, but, whatever. There are other operators we could use aside from “icontains”. “contains”, “startswith”, and “exact” are some others. You can see this gives you similar power to a SQL SELECT blah FROM blah WHERE… Again, Django is handling the ORM code for us so this is what we’ll use to query the Model.

Third: implement templates/search.html

Fourth: update urls.py
(r’^search/$’, search_page),

Now test it out:

Very cool. We’ve now created our base search functionality with a few lines of code. Now we can add in the AJAX for browsers that can handle it (have JavaScript enabled).

First: update base.html to have a link to the search page:

Second: update the views.py

Third: update the search.html

Fourth: create the search.js file. This…

Again, we can test it. Notice this time the page does not reload. That is the JQuery AJAX call handling the manipulation of the innerHTML of the page for you:

AJAX accomplished! It’s a brand new day. Next time I’ll be doing something a little more advanced, but this was a good start.

Thanks,
Mike

Django & Python Adventure Part 5

In this post I’ll be adding the Tag concept to my bookmarks website. This will get the website one step closer to what Delicious does and is an integral part of social websites. Throughout the course of the blog we’ll add Tags, and Tag Clouds into the website and give the user several ways to bounce between Tags and Bookmarks.

First we’ll need to add a model for the Tag in models.py:

PS-Notice that we have updated each model with a __unicode__ method. The old way you’ll see this is with __str__ which returns bytes instead of characters. The value of this is Django will use it to return a normal human language representation of whatever the model is under the hood.

Then re-issue the command prompt for syncing the database:
c:Python27django_bookmarks>python manage.py syncdb

Next I’ll add a form for the user to submit bookmarks and tags. Open forms.py

Next we need to create a View for this, so open up views.py

And finally we need a template and a url. So, create a file called “bookmark_save.html” in the templates folder. It will look similar to all the templates we’ve done in this series:

And edit your urls.py to look like this. The book suggests at this point to do some clean up, so you’ll notice the comments breaking urls out into functional areas.

Now you can browse to your save page:

Enter a few links and see how your user page grows:

Cool, but kind of sad that it doesn’t display the tags we’re duitifully entering, right? So a couple of things are in order to clean this up. We’ll begin with locking this page down to the proper users. Right now you can type different usernames in the URL and see their stuff. That wouldn’t fly for anyone. Open the templates/base.html:

Then we’re going to limit the access of the bookmark save page to only authenticated users. This could be hacked with an if-else statement, but Django provides a better way. Open views.py:

Pretty cool? Just an include and a decorator on your view definition tells it that the user must be authenticated. The last thing you need to do is add the following like (variable declaration) to the bottom of the settings.py:
LOGIN_URL = ‘/login/’

Now when you logout and try to browse directly to http://127.0.0.1:8000/save/ You will get:

Okay, so now it’s time to get User page to not only display our saved links but their tags as well. We’re going to do this by creating a template for displaying bookmarks and tags and then drop it into the user page.
Create a new template file called “bookmark_list.html”:

This template is less like a Master Page and more like a User Control. In the Classic ASP days it was just called an include file, or a code snippet. Wow, there are a lot of ways to say we’re going to hide this code so we can make it look like 1 line in other places ;-) So, now do that in your user_page.html:

Notice everything in the {% block content %} has been replaced with our include. We were dropping a lot of class definitions in the include file that don’t exist yet in our CSS file. So open up the style.css:

The last thing we need to do is update the user_page view definition to show the tags. You’ll notice a new Django function “get_object_or_404” in use here. It’s another if-else statement asking the database if it can retreive the user object and if it cannot it’s going to display a 404 error. Just like the old code, just streamlined.

Great, now you can check out your page at: http://127.0.0.1:8000/user/username/:

Next I’ll turn all the tags into their own pages so users can see all the links that match the tag.

Let’s start with urls.py. Add this definition to it:
(r’^tag/([^s]+)/$’, tag_page),

Then hop over to the views.py:

Then create a template page for the response called tag_page.html:

Then modify the part of bookmark_list.html that generates the Tags so that it creates a URL link to the tag page:
So, this line:

  • {{ tag.name }}
  • To this line:

  • {{ tag.name }}
  • Now if you refresh your User page you’ll notice the Tags are now links:

    And if you click on a link page you should see the associated bookmarks and the Posted By username:

    The final step in this chapter is on creating a tag cloud. If you hang out in WordPress blogs at all you’re probably familiar with the visual Tag Clouds that they often have on the side. The point is to show all the tags in the blog. Here it is to show the tags in our bookmark database. After that you want to be able to assign a “weight” to each tag based on how many “hits” or counts that tag has in the database. This is one of the cooler concepts that web 2.0 sites use. This sort of collective intellgence based on what the community is doing. Sound familiar? It’s was one of the big things I noticed when google’s search came out. Results sorted by “weight”. You see it as weight/rank/relevance depending on what site you’re on, but, in all cases, it’s pretty cool and I’d probably need a PhD to blog more on it :p.

    Okay so hop back over to views.py:

    And then create a template page for “tag_cloud_page.html” and put this code in:

    So, what’s going on? Nothing beyond a little math. We’re setting a range from 0 to 5 for each tag, and then calculating the weight based on how many tags there are in the database. Something I really think is cool is the dynamic CSS class assignment in the HTML. That’s how we’ll dynamically control the size of the cloud font to show which are more popular.
    So, pop open style.css:

    And finally we’ll update the urls.py:
    Add this line under the last one you did:
    (r’^tag/$’, tag_cloud_page),

    Then browse to http://127.0.0.1:8000/tag/

    Cool! It’s cooler if we add more bookmarks with tags, but you see the potential here. Okay, so there was a lot of code in this post. I am starting to get pretty used to the pattern of adding of content to the site. Bouncing between adding database models to views and templates and adding url paths for users to get to them. Although the site map is growing, there’s really only those main 3 pages I keep going to.

    Another thing I’ll note is at this point I’ve had to do some debugging a couple of times and I found the process pretty painless. Django’s debug messages point me directly to the problem it’s having. Either a type on the view, or the urls made up most bugs. If you get something wrong with your database model, you tend to notice it immediately.

    Django & Python Adventure Part 4

    In this post we’ll be dealing with Django’s User Authentication and Base Templates (Master Pages). These are things every project requires and so you cannot really know a platform until you’ve covered this ground.

    First let’s take care of the Base Template. In this part we’ll add a special kind of template that is used by other templates. If you’re a .Net person, this is a Master Page. If you’re some other kind of person…. Hiya! We’ll also add a style sheet to our project to handle a universal nav:
    In your project, add the following pieces:
    project folder

    So, a folder called “site_media” with a style.css in it and in the templates folder a base.html.
    styles.css will look like this:

    We’ve already included the auth library in the settings.py under the INSTALLED_APPS section, but we have to modify the MIDDLEWARE_CLASSES section to allow our sessions to save a cookie.
    Find that section and add this line to the list:

    'django.middleware.csrf.CsrfViewMiddleware',

    Now we can jump to the urls.py and setup a line to instantiate the authentication login view:

    (r'^login/$','django.contrib.auth.views.login'),

    Now add a folder to your templates directory called “registration” and add a page to that called “login.html” and paste in this code:

    IMPORTANT! That {% csrf_token %} was not in the book and took some research to figure out. Ultimately, it was this blog that got me past that bug: http://jordanmessina.com/2010/05/24/django-1-2-csrf-verification-failed/
    Otherwise, you get a nice 403 error telling you it’s missing.

    Now you can go to views.py and add in the following and replace your main_page definition:

    And redo the user_page function in the same page to use the render_to_reponse library:

    Now we’ll add a page “forms.py” in the bookmarks application folder.
    Here are the entire contents:

    Next you’ll need to update the views.py:

    It will come out like this:
    registration page

    Now we need to modify the top navigation to account for these new options, so edit your base.html nav id:

    Lastly we’ll implement a successful message page for the registration process. If you’ve noticed in this walk through Django provides a lot of functionality for you out of the box. Here is another example. There is a view inside the django.views.generic.simple library called direct_to_template.

    Create a register_success.html inside your templates/registration folder and enter this code in:

    Then update your urls.py:

    (r'^register/success/$', direct_to_template, {'template':'registration/register_success.html'})

    Tmie to test this out:
    registration form tested
    Hit register and:
    registration success
    (PS-if you’re paying attention you’ll notice the nav at the tops say’s “sa” and not “ishmael”. I had to logout of sa and do it again to get that to work right, but my post-production budget is tight)

    Afterthoughts: This took a bit more time for me to debug, and there’s probably some libraries that have changed since the book I’m reading. I noticed that PyCharm gave me a deprecation warning on this library: django.views.generic.simple, so that’s something I’ll check into later.

    Overall though, I’m impressed at how simple it was to add Authentication. Although this is something you do once per project, I’ve seen a lot of custom code that makes it extremely painful. For me, saving lines of code means simplicity which is what I’m going for. If you have any questions or comments, feel free to shoot them over.

    © Copyright Duke Hall - Designed by Pexeto