Friday, October 2, 2009

Django - Cannot convert float to Decimal

Ever see one of these?

Exception Type: TypeError
Exception Value:

Cannot convert float to Decimal. First convert the float to a string

This is caused by the fact that python cannot convert a float to a decimal. It is a feature of python, not a bug. The essence of the issue is that a float is a representation of a decimal number from binary. You don't really know what's exactly stored in a float, only that it is within some very close distance to the number you
want to be there. For example a float variable x assigned the value 24 might actually contain the value 24.000000000001. The variable x is close enough to 24 for most applications that you wouldn't mind the small discrepancy. A decimal variable, however, is an exact value. If you set decimal variable x to 24 then it is exactly 24. Converting a float to a decimal requires guesswork. Python's design philosophy seeks to avoid making guesses. Thus the programmer must handle that conversion explicitly.

I encountered this problem when importing a float value from the settings file.

import settings
from decimal import *

foo = Decimal(str(settings.FOO))
# foo will now work with django decimal model fields.

Thursday, September 10, 2009

Add a Group to a Django User

How to add a group programatically:
from django.contrib.auth.models import Group
...

# This adds a group to the group list

g = Group()
g.name="foo"
g.save()

# To add the group to a users group list

g = Group.objects.get(name="foo")
u = MyUser.objects.get(username="foo_user")
u.groups.add(g)
u.save()

# see the groups in u
u.groups.all()

Wednesday, September 9, 2009

Extending the User Model in Django

This custom backend allows you assign a subclass of the django user at login.

Say you have a custom user Foo:

class Foo(User):
magic = model.CharField(...)

when a Foo logs in you want him to be a Foo, and not a user. So when you
call
def bar(request)
user = request.user
# user is a Foo, automatically
user.magic = "card trick"
# works

This is an extension of
http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/

The only limitation as written is that it takes over the group attribute of the user
definition. The user object subclass will be the group name for the user. If no group
is assigned then the user is a standard User. This can be easily changed, but I don't need
the group functionality for my app.

Name the file auth_backends.py and put it at your app docroot.

Modify settings.py as such:
AUTHENTICATION_BACKENDS = (
'djdemo.auth_backends.CustomUserModelBackend',
)



It is my first django hack, so it is probably can be improved on in some way.

in settings.py

AUTHENTICATION_BACKENDS = (
'djdemo.auth_backends.CustomUserModelBackend',
)

to use:

Any user for which you want an extended class must have their group set
to the classname. This method takes over the group attribute, which works
fine for my application. If you need group capabilities they can be achieved
with a minor hack.

UPDATE!!!: When you create your users in the admin interface (after configuring it
for your custom users) you will need to set the group still. If you don't do this your users will come back with class User, and not your custom extensions.

Also, when you set up the user with the admin interface make sure the password is in salted form, i.e. if the password for your CustomUser is "foo" then it should read something like "sha$kdiee933334324238djfhskj" in the password field. If it reads "foo" then user can never authenticate.