Archive for June, 2009

An Important Question When Moving into Unknown Programming Territory

So you’re about to undertake a project that you have little experience with (whether it be the language) or little knowledge about at all. The first question to ask oneself is “What level do I need to be working at?”

Now, let’s say I want to write a web application, and I choose to use python-django. We start with a problem, say, ‘how do I create a user-login interface (i.e. a standard across websites - e-mail activation, etc). First, you should consider what levels are available to you. In this case, the levels (from top down) are as follows:

Django-App (Pre-Built)

Django-App (customized with Python)

Combingin Pre-Built Python Libraries That Each Do A Significant Piece (i.e. loggin in to website, storing a session)

Develop Using much smaller Python Modules that Each Do A Smaller Piece (handle an http request, parse html)

… (more levels)

Using C/C++ To Build Python modules and work with those

(lower than this is absurd for common web stuff usually!)

Often, developers can strangle themselves because they start working at too low of a level, instead of searching for higher-level solutions that will either work out of the box, or work with a small bit of customization (my preferred way). While more control is great - time is almost always a factor (plus if you use django, then you probably subscribe to the DRY principle (Don’t Repeat Yourself), and do this anyway!)

So before you start your next project, do your research (usually in the form of multiple google searches) and make sure you are operating at the correct level.

Tags: , , , ,

Extend the Django-registration Form - Adding the Extra Fields you Want

Django-registration is cool, but often you want to add some more fields to the Registration Form. At first, it doesn’t quite jump out at you how to do this. This blog post is all about how to add some extra fields into django-registration while having to write the least code. We’ll go through all the steps just because its nice to have completness. Let’s see what we can do.

I used easy_install django-registration, and it installed this egg file to my site-packages: django_registration-0.7-py2.5.egg

Steps:
1. Create your own app, ours is called ‘mynewapp’ (which is a very poor name, by the way), and add it to your settings.py file in the regular way by registering it under INSTALLED_APPS

2. In your app, create a model in your models.py file using this method: http://www.djangobook.com/en/1.0/chapter12/#cn222 and make sure to set the AUTH_PROFILE_MODULE in your settings.py file.

This model is the ‘extended’ fields that you want to see in the form, such as user ‘location’, ‘address’, or ‘favorite stripper’ to name a few example.

It should look something like this and should be in models.py:

from django.db import models
from django.contrib.auth.models import User
class ZProfile(models.Model):
user = models.ForeignKey(User, unique=True)
favorite_band = models.CharField(max_length=200, blank=True)

In our case, we created a class model called ZProfile. Then, we added this in our settings.py file:

AUTH_PROFILE_MODULE = "mynewapp.ZProfile"

Note: you MUST put ‘appname.ClassName’ NOT like ‘projectname.appname.modulename’ or anything like that. Our class is ZProfile (inside a module named something like zforms.py or something), our app is mynewapp.

3. Now create a new registration form for yourself. You can create a new python file, and name it like newform.py.In it, define new RegistrationFormZ that extends RegistrationForm; this should have the new fields you want to add, and also it should override the save() method of RegistrationForm (its superclass).
Something like this:

from django import forms
from registration.forms import RegistrationForm
from django.utils.translation import ugettext_lazy as _
from registrationz.models import ZProfile
from registration.models import RegistrationProfile
attrs_dict = { 'class': 'required' }
class RegistrationFormZ(RegistrationForm):
band = forms.CharField(widget=forms.TextInput(attrs=attrs_dict))
def save(self, profile_callback=None):
new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'],
password=self.cleaned_data['password1'],
email=self.cleaned_data['email'])
new_profile = ZProfile(user=new_user, favorite_band=self.cleaned_data['band'])
new_profile.save()
return new_user

So what we see is that when a new user account is created, so too do we create our profile account. Nice! But we’re not done yet.

We have to tell django-registration to use our new form, RegistrationFormZ, instead of the default RegistrationForm. Django-registration is well designed in that it lets just simply pass this in as a keyword argument to the ‘register’ view, specifying which registration form we want to use. This is done using url patterns. So, let’s create a urls.py file WITHIN OUR APP (i.e. within the app we created earlier) that looks something like ‘registration.urls’ (django-registration default). We only have to change the url pattern that maps to the register view, with this line:

url(r'^register/$',
register,
{'form_class' : RegistrationFormZ},
name='registration_register'),

Here is the whole of the urls.py inside my app, with this change:

from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from django.contrib.auth import views as auth_views

from registration.views import activate
from registration.views import register
from mynewapp.registrationz.formsz import RegistrationFormZ

urlpatterns = patterns('',
# Activation keys get matched by w+ instead of the more specific
# [a-fA-F0-9]{40} because a bad activation key should still get to the view;
# that way it can return a sensible "invalid key" message instead of a
# confusing 404.
url(r'^activate/(?Pw+)/$',
activate,
name='registration_activate'),
url(r'^login/$',
auth_views.login,
{'template_name': 'registration/login.html'},
name='auth_login'),
url(r'^logout/$',
auth_views.logout,
{'template_name': 'registration/logout.html'},
name='auth_logout'),
url(r'^password/change/$',
auth_views.password_change,
name='auth_password_change'),
url(r'^password/change/done/$',
auth_views.password_change_done,
name='auth_password_change_done'),
url(r'^password/reset/$',
auth_views.password_reset,
name='auth_password_reset'),
url(r'^password/reset/confirm/(?P[0-9A-Za-z]+)-(?P.+)/$',
auth_views.password_reset_confirm,
name='auth_password_reset_confirm'),
url(r'^password/reset/complete/$',
auth_views.password_reset_complete,
name='auth_password_reset_complete'),
url(r'^password/reset/done/$',
auth_views.password_reset_done,
name='auth_password_reset_done'),
url(r'^register/$',
register,
{'form_class' : RegistrationFormZeta},
name='registration_register'),
url(r'^register/complete/$',
direct_to_template,
{'template': 'registration/registration_complete.html'},
name='registration_complete'),
)

Now, you need to make sure to include this urls.py file in your PROJECT urls.py.

So go to your project’s global urls.py, and add these lines:

(r'^accounts/', include('myproject.mynewapp.urls')),
(r'^$', direct_to_template, { 'template': 'index.html' }, 'index'),

The first line simply includes the URL file that we created in our app; the second line uses direct_to_template notation, which means don’t do any djangoey stuff (i.e. dont’ redirect to a view) instead just show a plain static template. The second line is only necessary if you used those template files I provided a link to earlier (on the other blog), and you want to show your index.html when people go to your site.

Now, run python manage.py syncdb, and it should update the correct models. Now when you create a user account, it will created a profile for him/her that is accessible by calling the get_profile() method (because we created a ForeignKey relationship between our user and the profile account, remember?). This profile will have all the fields you defined, in our case, it just has one field, favorite_band (which I really don’t even have, sadly).

One thing, is that while the ‘management’ script to clean up expired users accounts works for RegistrationProfiles or whatever, you will probably have to modify this if you to say you also want to delete the user’s accompanying ZProfile as well when it is checking for expired accounts.

Hope this was helpful! Feel free to leave me a comment or question and I will try to reply.

Tags: , , , , , , , ,

Getting a Production Server Up and Running: Django, Ubuntu, Nginx, Apache, Subversion, Memcache, UFW(firewall)

This post is for those of you self-starters that have never set up a whole server for a serious project, and want to learn how. Here is the links that I found that helped me most in the process. Its about installing apache, django, ubuntu, mod-wsgi, nginx, and subversion.

The first step is to go through this guide:

The Django and Ubuntu Intrepid Almanac @ Irrational Exuberance

This assumes you have ubuntu installed - it shows how to get and install apache, nginx, and django.

Here is another similar one:

Installing Django on Ubuntu Intrepid: Django, Nginx, Apache, mod_wsgi, cmemcache | meppum.com

Now, you will need to set up subversion, these are the best links I found for that:

https://help.ubuntu.com/community/Subversion

http://www2.russbrooks.com:8000/2009/2/1/install-subversion-on-ubuntu-linux

http://articles.slicehost.com/2007/9/5/using-ssh-with-svnserve

http://svnbook.red-bean.com/en/1.1/ch04s02.html

If you have questions, feel free to ask them in the comments section.

Tags: , , , , , , ,