Friday, June 26, 2009

Lenovo S10e Netbook Review (vs. Asus Wind vs. Acer Aspire One)

Before I continue on with the Apache/Django series, I thought I'd post a review of the Lenovo S10e netbook. Netbooks still seem in their infancy that it's hard to pick the right one without wondering what smashing new feature is just around the corner.

Just to be clear this entire review is being typed on the netbook.

Initially upon seeing the Lenovo S10e I dismissed it. At a glance it didn't seem special, and compared to all the netbooks around it, it wasn't shiny and eye-catching. However, there were a few things that brought me back for a second look, and why I decided on this book for my Philly '09 trip:

  • It was the lightest (compared against an Asus Wind-120U and Acer Aspire One)
  • It had a 10.2" screen, again the largest of the comparasion models
  • It was black/dark so I didn't need to worry about the dirty-factor
In addition to that, I have discovered that...
  • Initially I was worried the right-shift key (which is moved to the right of the up arrow) would be problematic for typing. It's not. I haven't even noticed it.
  • I was also worried the keyboard would be way too small and would get in the way. Again, it doesn't. It's a comfortable size.
I've been using it now for a week, and there are definatly some factors that I do not care for...
  • The fan. Oh my gosh. It sounds like this "brrrr... (wait 2 seconds) brrrr... (wait 2 seconds) brrrr.... (wait 2 seconds) brrr...." On-off-on-off-on-off. It gets annoying.
  • When you close the lid the laptop just kinda, I'm not sure what it does. But when you re-open the lid hours later tapping the power button or hitting the space bar does... nothing! Maybe it's Windows or maybe I just don't use it right, but I end up having to hold the power button down, let it go completely off, and then reboot again. I wish it was more mac-like where I can just close the lid when I'm done, the netbook turns off in power-save, and then when I re-open it it powers up again.
  • The battery has two rear rubber feet, which when on a desk are nice, but when on your lap while sitting tend to jab into your thighs.
  • I miss having a "home" and "end" key, but I suppose that's the price you pay for a netbook. To be fair, there are home and end, but you have to press Fn+PgUp or Down to get them. It kinda defeats the quick home/end purpose of those keys.
Overall this netbook is a viable contender in the $400 market.

Thursday, June 18, 2009

Django, Apache 2.2, mod_ssl, and mod_wsgi (Part 3)

Part 1 | Part 2 | Part 3

Serving up Django
Following the completion of Part 2, we have an install of Django and Apache, and 2 virtual hosts running on it. What we need to do is connect those virtual hosts up to the content we need to serve.

Before we can do that, we need to add our Django app to the server. Create a folder on your webserver (anywhere really) that isn't in your document root (don't use htdocs). In my case I just made a folder off of the drive "Root_Django". Copy your django app folder into there. You should end up with something like...

C:\Root_Django\{nameofyourwebapp}

To connect Django up to Apache, we need to create a python file that will initialize WSGI and pass that information on to Django. In your {nameofwebapp} folder, create a sub folder named "apache", and then create a new file in that folder named "django.wsgi".

Paste this script into that file:

import os, sys
sys.path.append('C:\\Root_Django')
sys.path.append('C:\\Root_Django\\{nameofwebapp}')
os.environ['DJANGO_SETTINGS_MODULE'] = '{nameofwebapp}.settings'

# Remap stdout to err
sys.stdout = sys.stderr

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Be sure of course to change "{nameofwebapp}" to the actual name of your django application. This short script will take care of a few things...
  • the sys.path.append portion needs to point to your actual Django root. Adjust that if it's not C:\Root_Django
  • sys.stdout = sys.stderrd will redirect all "print" statements to the Apache error log. If you don't have any print statements in your code you can drop this, but I prefer to keep it "just in case"
This script will take care of initializing Django. All we need to do is connect up the requests to our apache virtual host to this script. Edit httpd.confi, and inside of the virtual host for your "www" host, add these lines:
WSGIScriptAlias / C:\Root_Django\{nameofwebapp}\apache\django.wsgi

<Directory "C:\Root_Django\{nameofwebapp}">
Order deny,allow
Allow from all
</Directory>
This tells Apache that all requests coming in from / and up should be handled through the django.wsgi script. Save your httpd.conf file and restart Apache. You should see your Django app being served up now, minus the media (images, css, etc.).

Serving up Static Media
So you're serving python now, but your web app without images and css is pretty limp right?

Here's what we need to do:
  • Configure an Apache virtual host to serve our static media
  • Configure Django to know the correct place for our media
  • Make sure we're also serving the grappelli media instead of the default admin media
Open up your httpd.conf file again, and find the Virtual host for your media.example.com (or whatever your static host name is). Since this will just be basic serving without WSGI, we simply need to configur the document root to the proper location...
DocumentRoot "C:\Root_Django\{nameofwebapp}\media"
<Directory "C:\Root_Django\{nameofwebapp}\media">
Order deny,allow
Allow from all
</Directory>
Tada! If you were to save and restart apache, then navigation to media.example.com/some/css/file.css it should work. What we still need is to serve up the grappelli media. To do this we'll add another alias so that media.example.com/admin will serve the grappelli content.
Alias /admin "C:\Root_Django\{nameofwebapp}\grappelli\media"

<Directory "C:\Root_Django\{nameofwebapp}\grappelli\media">
Order deny,allow
Allow from all
</Directory>
This will make sure that all requests to /admin on your media host will serve the grappelli media files. If you installed grappelli into your Python site-packages folder, be sure to set the path to that folder instead of the django root like shown above.

Configure Django With Media Prefixes
Lastly for this section, we need to do some configuration in Django.

In Part 1 we installed grappelli but we haven't configured it, so we'll do that now. Also, we're using a static media virtual host, so we need to make sure that Django is prefixing our media files correctly. All of this takes place in the settings.py file.

Configure grappelli
If you'd rather see the officiall grappelli installation instructions, they are available on the grappelli google code wiki.

First, add grappelli to the content processors:

TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.request",
"grappelli.context_processors.admin_url",
)
Next, add the grappelli template directory:

import os
here = lambda x: os.path.join(os.path.abspath(os.path.dirname(__file__)), x)
TEMPLATE_DIRS = (
# ...
here('grappelli/templates/'),
)
Lastly, of course, add grappelli to your list of installed apps:

INSTALLED_APPS = (
# ...
'grappelli',
)
Configure Media Prefixes
We want to configure Django to automatically insert "http://media.example.com/" in front of all of our media files. The setting in the settings.py to do this is:

MEDIA_URL = 'http://media.example.com/'
But this could easily become problematic when we're testing django with runserver. A better result would be to conditionally test if we're in DEBUG mode, and to change the value based on that.
if DEBUG:
MEDIA_URL = '/media/'
else:
MEDIA_URL = 'http://media.example.com/'
We'll also want to make sure the admin media files from grappelli are being served. The code is almost identical, expect the setting is ADMIN_MEDIA_PREFIX:
if DEBUG:
ADMIN_MEDIA_PREFIX = '/grappelli/media/'
else:
ADMIN_MEDIA_PREFIX = 'http://media.example.com/admin/'
At this point Django should be running, and serving media files.

Still to come:
  • Configuring HTTPS
  • Forcing HTTPS for django admin

Wednesday, June 17, 2009

Django, Apache 2.2, mod_ssl, and mod_wsgi (Part 2)

Part 1 | Part 2 | Part 3

DNS
I'm going to make an assumption. You have 1 domain and can create hosts under that domain. Fr example, say you own example.com. I'm assuming you have the ability to create "media.example.com" with whomever hosts your DNS.

You'll want to setup 2 domains:
www.example.com
media.example.com

Since this process is virtually different for everyone I won't cover it. Contact your DNS provider for assistance here.

Setting up Apache
If you've never used Apache, you can pretty much control the entire webserver from 1 file: httpd.conf. By default it's located in {apache install direcotory}\conf\httpd.conf. I like to edit it in Wordpad becuase I'm a lightweight, but you're welcome to edit it in whatever hacker-rific editor you prefer.

Installing mod_wsgi
mod_wsgi is a module addon for Apache which is responsible for accepting the incoming HTTP connection, turning that connection into a python object, and then passing it to Django. In other words, it's really important.

  • Copy the .so file you downloaded into {apache install directory}\modules.
  • Open the httpd.conf file and find the section that has all the "LoadModule"s in it
  • Add this line:
    LoadModule wsgi_module modules/mod_wsgi.so
  • This will load the wgi module whenever Apache runs
Configuring Virtual Hosts
Let's recall what our objectives for this project are:
  • Serve up Django with mod_wsgi by default from the site root
  • Serve up static media (images, css, js, etc.) from a separate virtual host
  • Offer the Django app in both HTTP and HTTPS
To achieve this, we'll need to setup at least 2 virtual hosts:
  1. to hold the Django application
  2. to hold all of our static media
We'll also need a way to configure Django to know where our static virtual host is.

In case you're wondering, there are a few reasons why this is an ideal setup:
  1. We want our Django application to worry about 1 thing: serving up python
  2. It would probably be a performance hit if python had to process all of our media files. It makes more sense to have them directly served by apache
  3. We can enable caching for everything on our static media virtual host, also improving performance
  4. It's uber leet cool (no, not really)
You can create virtual hosts in apache with the directive. Here's a sample of 2 virtual hosts:

NameVirtualHost *:80

<VirtualHost *:80>
ServerName www.example.com:80
ServerAdmin you@example.com
</virtualhost>

<VirtualHost *:80>
ServerName media.example.com:80
ServerAdmin you@example.com
</VirtualHost>

This will give us 2 domains to serve from.

Still to come....
  • Configuring wsgi and django
  • Configuring django settings to use our virtual hosts
  • Adding https support
  • Forcing /admin to use https only



Django, Apache 2.2, mod_ssl, and mod_wsgi (Part 1)

Part 1 | Part 2 | Part 3

It's funny how experience changes your perspective on things. 5 years ago I tried apache and thought it was too hard. "Why can't I just have a GUI to click the settings I want?!?" I would think in frustration. Now that I'm making the transition to Django, I thought I'd give Apache another try. Wow -- What a luxury it is to be able to just write a config file to do exactly what you want to do and not have to monkey around with where some stupid settings is in an extensive maze of windows and tabs. Hah... how times change indeed.

Anyways, here's a bit about setting up Django with Apache. Here's what will be achieved:

  • Serve up Django with mod_wsgi by default from the site root
  • Serve up static media (images, css, js, etc.) from a separate virtual host
  • Offer the Django app in both HTTP and HTTPS
  • Force the Django admin to always use HTTPS
  • Use django-grappelli for a slicker looking Django admin, as well as some other goodies
  • And lastly... do all this on a Windows Server (hah)
Installing Software
If you're following along at home, here's the list of things you'll need to download for a complete deployment:
Install all of the above, accepting the defaults (unless you otherwise know what you're doing). For mod_wsgi I'll cover installation in the next part, so hang onto it for now.

Now we'll need to do 2 SVN checkouts of code...

Installing the latest Django trunk from SVN
(note: this method will have the Django development trunk as your production copy of Django. If you don't like that, then just use the installer or the tar/zip from the Django site).
  • In your python install directory (default: C:\Python26) open Lib and then site-packages
  • Create a new folder named "django"
  • Right-click on that folder and choose "SVN Checkout" (this will launch TortoiseSVN)
  • Paste this URL into that window:
    http://code.djangoproject.com/svn/django/trunk/django
You've now got a fresh copy of Django, but we need to configure Windows to be able to find Python and the Django tools.
  • Right-click "My Computer" and choose Properties (this might be slightly different for Vista+)
  • "Advanced" tab
  • "Environment Variables" at the bottom
  • In the "System variables" list, find "Path"
  • Highlight it, and hit "Edit"
  • Add this value to the end of it (change the path to your python path if it's not default):
    C:\Python26;C:\Python26\Lib\site-packages\django\bin;
Now you'll want to test to make sure this works.

Open a command prompt and type "python" and hit enter. Python should run. Ctrl+Z out of that, and type "django-admin.py help" and hit enter. It also should run.

Django and python are good to go.

Installing grappelli
This next part uses my preferences. You can do this different if you want, but keep in mind you'll need to adjust paths later on to account for your differences.

I like to install my django re-usable apps into my project directory. This adds them to the SVN trunk and I don't have to worry about if others in the office have the app installed on their local machine or not.

Anyways, open your Django project (the site you've made), and create a new folder called "grappelli". Right-click that folder and choose "SVN Checkout". Paste this URL and hit ok:

http://django-grappelli.googlecode.com/svn/trunk/grappelli

It should download a copy of grappelli. We'll look at adding it to Django in the next part.

Wednesday, June 10, 2009

Desktop :: June


Vista Desktop, June 09, originally uploaded by wastingtape.

My desktop for June

OS: Windows XP
Wallpaper: Watercolor Emico
Dock: RKLauncher
Dock Skin: AluCurved3D
Desktop Info: Samurize

Saturday, June 6, 2009

Determine Model Change v2

Well I got around to doing a 2nd revision on my model change code (being the weekend I was wondering if it would come to pass). Per a suggestion by "thepointer" (#django IRC on freenode), I switched the code from using Python's generic vars() to Django's interal _meta. Using an internal API is probably not the ultimate best, but _meta has been stable and unchanged for quite a while.

I also added a "human_friendly" mode, which will take the model change and attempt to turn it into an understandable statement (string) about what exactly has changed. It still returns it in a dictionary with the field name as the key.

from django.db import models

def determine_model_change(old_model, new_model, human_friendly=False, ignore_fields={}):
"""
Compares the two models against each other, returning a dictionary of
values that have changed (new value only).

Setting human_friendly=True will cause ignore internal fields like
SlugField. It will also attempt to parse a meaningful statement for
the model change. ie 'Event date is now 5/7/2009'
"""
not_human_fields = (
models.fields.SlugField,

models.fields.FilePathField,
models.IPAddressField,
models.FileField,
models.ImageField,
models.XMLField,
)
changed = {}

if isinstance(old_model, models.Model) and isinstance(new_model, models.Model):
for f in new_model._meta.fields:
if not f.name in ignore_fields:
new_value = getattr(new_model, f.name, '')
old_value = getattr(old_model, f.name, '')
if cmp(new_value, old_value) != 0:
if human_friendly:
if not type(f) in not_human_fields:
changed[f.name] = __verbose_field_change(old_model, new_model, f)
else:
changed[f.name] = new_value

return changed

def __verbose_field_change(old_model, new_model, field):
"""
Returns the human-friendly text for a field change
"""
value = getattr(new_model, field.name)
if isinstance(field, models.fields.DateField) or \
isinstance(field, models.fields.TimeField) or \
isinstance(field, models.fields.DateTimeField):

value = value.strftime('%b %d, %Y %I:%M %p')
return '%s %s has changed to %s' % (
old_model,
field.verbose_name,
value
)


# -------------
# Sample usage:
# -------------

>>>
>>> from happenings.models import *
>>> import copy, datetime
>>>
>>> event = Event.objects.get(pk=1)
>>> event.name = "My Birthday"
>>> event.start_time = datetime.datetime(2009, 7, 5, 0, 0)
>>>
>>> newevent = copy.copy(event)
>>> newevent.start_time = datetime.datetime(2009, 7, 15, 0, 0)
>>>
>>> determine_model_change(event, newevent)
{'start_time': datetime.datetime(2009, 7, 15, 0, 0)}
>>>
>>> determine_model_change(event, newevent, human_friendly=True)
{'start_time': 'My Birthday start time has changed to Jul 15, 2009 12:00 AM'}

Easier, Faster Property Enumeration in Python

I just discovered a really neat trick in Python to take a collection of objects, and turn one of their properties into a list. It's not terribly difficult to perform this the old way...

subscribers = []
for subscription in self.subscriptions.all():
subscribers.append(subscription.user)
return subscribers
This would return something like [(User:bob),(User:jerry),(User:tim)] and so on. However, this can be done in just a single line...
return [s.user for s in self.subscriptions.all()]
+1 for Python coolness.

Friday, June 5, 2009

Django Model Comparison

I started working more with django-notification today. However, my implementation (outside of Pynax) is to create a subscription app, particularly for subscribing to event or calendar updates. Using Django's signals, I've got most of it setup. What I needed was a way to tell the difference between the old and new event, so that the notification could actually tell you "The start time for Event X has changed to Y:ZX" instead of "An event you're watching has been updated!".

So to do that I needed some model comparision code. Here's version 1.


def determine_model_change(old_model, new_model):
"""
Compares the two models against each other, returning a dictionary of

values that have changed (new value only).
"""
new_values = vars(new_model)
old_values = vars(old_model)

changed = {}

for key in new_values:

# Skip internal and 'magical' properties
if not key.startswith('_'):
if key in old_values:

if cmp(new_values[key], old_values[key])!= 0:

changed[key] = new_values[key]
else:

# Save the new value if it is not in the old values
changed[key] = new_values[key]
return changed

# Sample run:
# >>> class SomeModel(models.Model):
# >>> name = models.CharField()
# >>> age = models.IntegerField()

# >>>
# >>> foo1 = SomeModel()
# >>> foo1.name = "Some Model Name"
# >>> foo1.age = 14
# >>>
# >>> foo2 = SomeModel()

# >>> foo2.name = "Foo Model 2"
# >>> foo2.age = 14
# >>>
# >>> determine_model_change(foo1, foo2)
# {'name': 'Foo Model 2'}

Ignoring .pyc files in NetBeans

I started using the Netbeans 6.5 Python (Early Access) IDE a couple of weeks ago, and while all seemed to be going well, one thing that bugged me was seeing all the .pyc (python compiled file) in the treeviews. Turns out NetBeans has a simple way to fix this:

  • On the menu go to Tools > Options
  • Then "Miscellaneous"
  • Then "Files" tab
  • And find the section "Files Ignored by the IDE"
This value is a regular expression which makes it easy to add the functionality we're looking for.

Change this:
^(CVS|SCCS|vssver.?\.scc|#.*#|%.*%|_svn)$|~$|^\.(?!htaccess$).*$

To this:
^(CVS|SCCS|vssver.?\.scc|#.*#|%.*%|_svn)$|~$|^\.(?!htaccess$)|pyc.*$


You could easily use this method for any other file type you'd like to ignore. Just add "|extension" before the .*$.

  © Blogger template 'Minimalist G' by Ourblogtemplates.com 2008

Back to TOP