Archive | Featured

Tags: ,

Adding Views to the Django Admin

Posted on 26 March 2010 by BeardyGeek

I recently had to write a view that exported data to csv.  The view had to be contained within the Django admin area, on a separate page from the rest of the apps and models.  Here is the approach I took.

The Urls

There are 2 ways to add urls to the admin: the quick and easy way, or the not so quick and easy way.  In this case, as I was only adding a single url, I went for the quick and easy way.  The other way involves extending the get_urls() method of AdminSite, adding to the existing admin url pattern.  I did this:


(r'^admin/mypage/$', 'myapp.views.my_admin_view'),
(r'^admin/', include(admin.site.urls)),

Make sure you add your page before the main admin include.

The View

When you write your view make sure you use the staff_member_required decorator.


from django.contrib.admin.views.decorators import staff_member_required
...
@staff_member_required
def my_admin_view(request):
    # view code

When rendering your view, also make sure you pass RequestContext to the template:


return render_to_response('my_template.html',
  context_instance=RequestContext(request))

The Template

So that your view looks like it belongs in the admin area, you need to extend the admin base site template:


{% extends 'admin/base_site.html' %}

You’ll also want to add in i18n support, and the admin media:


{% load i18n adminmedia %}

If you want to add in extra styles you can use {% block extrastyle %}, and you could put javascript in {% block extrahead %}.

Adding form date widgets

If you have a form on your page that includes date fields, you might want to have the nice django javascript form widgets. First you need to add the widgets to your form:


from django.contrib.admin import widgets

class AdminForm(forms.Form):
    start_date = forms.DateField(label="Start date",
         widget=widgets.AdminDateWidget())

Next you need to add in the following to your extrahead block (replace admin-media with whatever you’ve set your admin media url to):


<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/admin-media/js/core.js"></script>
{{ form.media }}

You also need to add the admin forms css in the extrastyles block:

{{ block.super }}
<link rel="stylesheet" type="text/css" href="/admin-media/css/forms.css" />

Breadcrumbs

If you want to have the breadcrumb trail at the top of the page, you need to create your own breadcrumb:


{% block breadcrumbs %}<div class="breadcrumbs"><a href="/admin/">
{% trans "Home" %}</a> > My View</div>{% endblock %}

Adding a link to the admin index

When I add a link in, I like it to go in one of the right column boxes, so I usually create a new one and put it above the recent actions box. To do this, you need to override the admin index.html file.

Create a directory in your templates directory called admin. Then copy the index.html file from django/contrib/admin/templates to your new directory.

You’ll see a block called ’sidebar’. Under the ‘content-related’ div, place the following:


<div class="module">
  <h2>Admin tools</h2>
    <ul class="actionlist">
      <li class="changelink">
        <a href="/admin/mypage/">My View</a>
      </li>
    </ul>
</div>

Enjoy!

Comments

Tags:

New Django Site – The Great British Sleep Survey

Posted on 24 March 2010 by BeardyGeek

I’ve very recently finished a django based site for a company called Sleepio.  The project was to create a survey site, called the Great British Sleep Survey. Once completed, it calculates your sleep score and creates a report tailored to your issues (or lack of).

Also working on the site, doing all the xhtml and css magic was Rui Zhang from borderleft. If you ever need anyone to turn your designs into an actual web site, he’s your man. Thanks Rui.

One of the co-founders of Sleepio is Professor Colin Espie, who runs the sleep centre at Glasgow University.  The site is also a collaboration with Boots Web MD, which offers health and medical advice.

So check it out, complete the survey (you get a free sleep report!), and any feedback is always welcome.

Comments

Tags:

Google Calls for Link Spam Reports

Posted on 04 March 2010 by BeardyGeek

Spam

[image attribution]

In Matt Cutts latest blog post, he calls for users to report any sites they deem ’spammy’. On the report form, this includes anything that is considered:

  • Hidden text or links
  • Misleading or repeated words

Matt says that Google have been working on new algorithms to detect link spam, and it seems that through this manual reporting process, Google users will be helping to ‘train’ the system to be more effective.

It doesn’t say yet what action will be taken upon finding such a page, and whether Google will allow webmasters to make amends or defend themselves.  So look out for tales of woe from people removed from Google’s index for spurious reasons.

Comments

Tags: ,

How to Call a .Net Webservice using Python

Posted on 01 January 2009 by BeardyGeek

My day job involves working with software that automatically creates webservices on the .Net platform. Up until now I have used C# to create web applications to use these webservices.

But it would be nice to have the flexibility to use another programming language to create a solutions, and consume the webservices from there.

So, here’s a short tutorial on calling your .net webservice using Python.

Pre-requisites

  1. I’m currently using Python 2.5, so I can’t speak for other versions
  2. You will need the ElementSoap package from effbot.org. You can get it from here
  3. You’re also going to need a .Net webservice with which to test this out. If you’re reading this tutorial, you probably already have one.

SOAP

Firstly we need to look at the SOAP examples on your .Net webservice. Go your webservice’s asmx page, and then click on one of your webservices to view the details. You will see some example SOAP requests and responses. The one we’re interested in here is SOAP 1.1. Mine looks like this:


POST /lookserver/webservices.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/GetVersion"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getVersion xmlns="http://tempuri.org/" />
  </soap:Body>
</soap:Envelope>

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getVersionResponse xmlns="http://tempuri.org/">
      <getVersionResult>string</getVersionResult>
    </getVersionResponse>
  </soap:Body>
</soap:Envelope>

As we can see here, I have a webservice called GetVersion, the namespace is http://tempuri.org, and the SOAPAction is http://tempuri.org/GetVersion. Note these down for your webservice.

Into the Python

Fire up an interactive session, and we’ll go through calling this service.

Firstly we need to import the ElementSOAP library:

from elementsoap import ElementSOAP as ES

If you get an error message, then you haven’t installed ElementSoap properly.

Next we create a SoapRequest:

sr = ES.SoapRequest("{http://tempuri.org/}GetVersion")

And now we initialize a SoapService object:

serv = ES.SoapService("http://localhost/lookserver/webservices.asmx")

Obviously put in your own url for your webservice.

Now we call the webservice, using the SOAPAction value:

result = serv.call("http://tempuri.org/GetVersion", sr)

The result is an xml element which should contain the response from your webservice. When I type result I get:

<element '{http://tempuri.org/}GetVersionResponse' at 00A1A8A8>

If you look at the xml at the top of the article, you’ll see that the result returns inside a GetVersionResponse tag. To get the value of the result we type:

result.find("{http://tempuri.org/}GetVersionResult").text

This finds the appropriate tag, and returns the text.

 

Conclusion

I hope this has helped. When I searched, I found that the other tutorials were either confusing, or out of date. Take a look at the various libraries at effbot.org, especially ElementTree for parsing XML, very useful. Enjoy!

Comments

Tags:

Creating User Profiles with Image Thumbnails in Django

Posted on 20 November 2008 by BeardyGeek

I am currently working on a django application that will include a profile page for each user. Like many web apps, it will have the ability to upload a profile picture, and have this picture shrunk to a suitable thumbnail size.

To complicate matters, I want the photo uploaded to a directory which will be named after the user.

I’m fairly new to Django, so it took some time to piece this all together, but someone out there may have had the same problems and I hope this post helps.

Prerequisites

You must have the Python Imaging Library installed. You can get this from the PIL homepage.

User Profiles

The first thing we need to do is create a model for our user profile.

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    nickname = models.CharField(max_length=50, blank=True, null=True)
    photo = models.ImageField(upload_to='profile_pics', blank=True, null=True)
    thumbnail = models.ImageField(upload_to='profile_thumb', blank=True, null=True,
          editable=False)

I’ve made the upload_to attributes static for the time being, but we will be changing this later.

User Profile Setup

So that Django knows which model to use for you user profile, you have to add a setting to your settings file.


AUTH_PROFILE_MODULE = 'appname.UserProfile'

Make sure that this uses your app name, not your project name. I’ve used UserProfile for the model, but you can call it whatever you like.

Dynamic Upload Directory

To make the upload_to attribute dynamic based on the current user, we have to write a small function that returns the appropriately formed path. My thanks to Josh Ourisman and his post for this part.

Create a file called files.py and save it in your application directory.


def get_profile_path(instance, filename)
    dir = "%s/profile_pics/%s" % (instance.user, filename)
    return dir

This will make the profile picture save in the directory ‘username/profile_pics/filename’. You can move these around if you want a different directory structure. The MEDIA_ROOT value from your settings file will be prepended to this path automatically, so make sure you set that.

Amend the Model

Now back to our model, where we call our new function from the upload_to attribute.


from projname.appname.files import get_profile_path

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    nickname = models.CharField(max_length=50, blank=True, null=True)
    photo = models.ImageField(upload_to='get_profile_path', blank=True, null=True)
    thumbnail = models.ImageField(upload_to='profile_thumb', blank=True, null=True,
         editable=False)

We will leave the thumbnail upload_to field, as we will be dealing with that one manually.

Creating the View

I wanted to just create one view that would handle creating a new profile, and displaying and updating an existing profile. First I’ll create a form to display in the view.


from django import forms
from django.forms import ModelForm
from projname.appname.models import UserProfile

class UserProfileForm(ModelForm):
    class Meta:
        model = UserProfile
        exclude = ('user')

Now to the view


from django.shortcuts import render_to_response
from django.template import RequestContext
from famblog.blog.forms import UserProfileForm
from famblog.blog.models import UserProfile

from django.contrib.auth.decorators import login_required

@login_required
def profile(request):
    try:
        myprofile = request.user.get_profile()
    except:
        up = UserProfile(user=request.user)
        up.save()
        myprofile = request.user.get_profile()

    if request.method == 'POST':
        f = UserProfileForm(request.POST, request.FILES, instance=myprofile)
        if f.is_valid():
            f.save()
    else:
        f = UserProfileForm(instance=myprofile)

    return render_to_response('appname/profile.html', {'f':f, 'profile':myprofile},
        context_instance = RequestContext(request))

This view will try and retrieve the user profile based on the current logged in user. If the user profile doesn’t exist, then an exception is thrown. If this happens, we create a profile with just the username and call get_profile() again. We then deal either with a POST event, or we bind the retrieved profile instance to the form ready for updating by the user.

If you don’t want to create thumbnails of your images, you can leave it here. The images will have been loaded

Thumbnail Creation

To create the thumbnail, we now need to override the save def in our model.


def save(self, force_insert=False, force_update=False):
        #get mtime stats from file
        thumb_update = False

        if self.thumbnail:
            statinfo1 = os.stat(self.photo.path)
            statinfo2 = os.stat(self.thumbnail.path)
            if statinfo1 > statinfo2:
                thumb_update = True

        if self.photo and not self.thumbnail or thumb_update:
            from PIL import Image

            THUMB_SIZE = (150, 150)

            #self.thumbnail = self.photo

            image = Image.open(self.photo.path)

            if image.mode not in ('L', 'RGB'):
                image = image.convert('RGB')

            image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
            (head, tail) = os.path.split(self.photo.path)
            (a, b) = os.path.split(self.photo.name)

            if not os.path.isdir(head + '/thumbs'):
                os.mkdir(head + '/thumbs')

            image.save(head + '\\thumbs\\' + tail)

            self.thumbnail = a + '/thumbs/' + b

        super(UserProfile, self).save()

First we set a thumb_update var to false. Then, if the thumbnail exists, we check to see if the timestamp on the original image is newer than the existing thumbnail. If we didn’t check for this, then when we changed the image, we wouldn’t know whether or not to create the thumbnail.

The rest of the code deals with using the Imaging Library to resize the image. It also creates a ‘thumbs’ directory if one doesn’t already exist, saves the image, and updates the ‘thumbnail’ field in the model.

Conclusion

I hope this has been helpful. Like I said, I haven’t been using Django or Python for more than a few weeks, so if anyone has any suggestions for improving this code, then please comment.

Enjoy!

Comments

Tags: , ,

Django Template Auto-completion in Eclipse

Posted on 11 November 2008 by BeardyGeek

I’ve just recently started using Django and I wanted to set up an IDE for some coding niceties.

I already use Eclipse for PHP development, so I installed the PyDev plugin for Eclipse.

Now I get autocomplete in the py files, but when writing the Django html templates, there is no autocomplete for the various template tags.

So here’s a quick guide to adding your own tags in Eclipse.

  1. In Eclipse, go to Window->Preferences
  2. Go down to Web and XML.
  3. Then to HTML files and finally Templates
  4. You will see a list of all the various HTML templates there.
  5. Click on New.
  6. Give your tag a name. It can’t be one that’s already taken, but I found I didn’t have any issues. If you want to keep them all together you could start your tag name with ‘DJ’.
  7. Select HTML Tag from the drop down.
  8. Give your tag a description.
  9. Type in the the tag pattern. If you want the full tag on autocomplete, you might type in {% block ${cursor} %}, otherwise you could start with block, which means you would need to type in the {% and then activate the autocomplete in the HTML editor. The ${cursor} places the cursor where you want it after the tag has been inserted.
  10. Click Apply and OK.
  11. Test this out in the HTML editor. Press CTRL and Space. You should get a list of available tags. Type b (or what ever the first character is for you tag name), and you’ll see your block tag with the description next to it.
  12. Press enter, and your tag will appear.

Hopefully this will make your Django coding a little easier.

Comments

Tags: , ,

Web 3.0 – How to put Semantic Tags in your Blog

Posted on 01 March 2008 by BeardyGeek

I read the other day how Yahoo was going to start supporting semantic web standards.

The semantic web is something that is often associated with Web 3.0 (if that’s what you want to call it!), and will allow greater data exchange, better and more targeted search, and generally open things up for a super mash-up. Take a look at Wikipedia’s definition of Web 3.0 for more info.

One of the formats that Yahoo will initially support is hAtom, which is a microformat especially for blog entries.

So, I thought I’d take a look at it and try and implement it in the BeardyGeek blog.

First Steps

To add an hAtom feed to your blog, all you need to do is add some class names to what are probably existing divs or spans in your blog template.

For example, if you have a div around your entire content that looks like this:

<div class=”content”>

you just need to add an extra class tag called hfeed:

<div class=”content hfeed”>

To have more than one class, just separate them with a space.

There are 3 more main tags that you need.

  • hentry – the outer tag for each blog post
  • entry-title - the tag for the post title
  • entry-content – the tag for your post content

And that’s it. Easy as pie!

How I changed my Wordpress Theme

Ok, here’s what I changed in my theme.

Header page – At or near the bottom is a div tag – <div class=”content”> – I changed that to <div class=”content hfeed”>.

Single Post - I added the hentry tag to <div class=”post”> so it now read <div class=”post hentry”>. I then added entry-title to the <h2 class=”post-title”> so it read <h2 class=”post-title entry-title”>. And I also add entry-content to <div class=”postentry”> so it read <div class=”postentry entry-content”>.

Main index template – pretty much the same as the single post page, as the tags are all the same.

Testing

To test the feed, I downloaded Greasemonkey plugin for Firefox. I then downloaded the RSS Panel X script for Greasemonkey, which allows you to view a page’s feeds in a small JavaScript window. This is ideal for testing in this case as it supports hAtom.

Once you have these installed and running (tip: install the plugin first, then the script installs automatically), just load up your blog page. If all went according to plan, you should see your hAtom feed along with your RSS feed.

In fact, you can test it out here, as I have my hAtom feed up and running!

Good luck, let me know how you get on.

Comments


Twitter Buttons