18

I have a couple of tables that are joined by GUIDs in SQL Server. Now, I've found a few custom fields to add support for GUIDs in django, but I tend to shy away from using code in blog posts if at all possible. I'm not going to do anything with the GUID other than join on it and maybe assign a GUID on new entries (although this is optional). Is there any way to allow this using django's built-in types? Like can I use some kind of char field or binary field and "trick" django into joining using it?

If it's any help, I'm using django-pyodbc.

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • Why does the guid have to be a primary key? Can it not be just an indexed column and a regular char field? After initially converting all the tables into django "models" adding any new product etc... will require you to set a guid but you will have access to another table through django foreign key – Andriy Drozdyuk May 26 '09 at 17:16
  • I suppose that's a good question. Hadn't really thought about it. :-) – Jason Baker May 26 '09 at 23:51

6 Answers6

19

I'd create a basic GUID Model in order to reuse it's properties for any other models in my projects. Model inheritance is working nicely since several versions prior to Django 1.0 and is quite stable with Django 1.0.

Create something like project/common/models.py and place there this class:

import hashlib
import random
from django.db import models

class GUIDModel(models.Model):

    guid = models.CharField(primary_key=True, max_length=40)

    def save(self, *args, **kwargs):

      if not self.guid:
        self.guid = hashlib.sha1(str(random.random())).hexdigest()

      super(GUIDModel, self).save(*args, **kwargs)

Then create your other models as usual:

from common.models import GUIDModel

class Customer(GUIDModel):
  name = models.CharField(max_length=64)

class Product(GUIDModel):
  name = models.CharField(max_length=64)

class Sale(GUIDModel):
  customer = models.ForeignKey(Customer)
  product = models.ForeignKey(Product)
  items = models.PositiveIntegerField()

And everything should work nicely with GUIDs as primary keys instead of autoincremental integers.

gnrfan
  • 19,071
  • 1
  • 21
  • 12
  • 10
    I might suggest using the python uuid module and generating new guids either with uuid.uuid1() or uuid.uuid4(). – Craig Trader Jul 31 '10 at 20:14
  • 2
    To make this code work with forms, you need to add blank=True to the GUIDModel. This allows the form to validate; we never actually end up with a blank guid because save() ensures that there is a value. – Rich Sep 12 '10 at 09:13
  • 10
    Shouldn't you add `abstract = True` under `class Meta:` for the GUIDModel; otherwise I think Django will think all of them point to a central table... – Jordan Reiter Mar 03 '11 at 17:39
  • 12
    The code to generate "GUIDs" is extremely wrong. As Craig says, use uuid.uuid4() rather than reinventing this. If you must reinvent this, there's a spec for how you generate GUIDs - RFC4122. For random GUIDs, you need 122 bits of good-quality random number; but you have at most 53 bits of randomness, and it's not clear how good the seed is. (Source: http://docs.python.org/library/random.html says random.random() "produces 53-bit precision floats"). 6 of the bits in the GUID have to be set to specific values to indicate it's a random GUID, and you're not doing that. – user9876 Aug 17 '12 at 13:37
8

Take a look at Django-extensions UUID Field

Jj.
  • 3,160
  • 25
  • 31
  • It is an old question but I have memory like a sieve. this looks like a link to old Google code repository rather than the newere github link which akotian has put in. – hum3 Jun 22 '17 at 14:52
  • 1
    Good call @hum3 I updated the link to the github repo. – Jj. Jun 23 '17 at 05:16
6

Old question, but for anybody using Django 1.8+ the built in UUIDField could come in handy.

akotian
  • 3,885
  • 1
  • 33
  • 44
  • Links to newer documentation. The latest dev link is [UUIDField](https://docs.djangoproject.com/en/dev/ref/models/fields/#uuidfield) but probably should look a version back. – hum3 Jun 22 '17 at 14:58
1

Django has now included UUID Field in 1.8 and above. A field for storing universally unique identifiers. Uses Python’s UUID class. When used on PostgreSQL, this stores in a uuid datatype, otherwise in a char(32). This field is generally used as a primary key and here is how you can use it with models ->

your_app/models.py

import uuid
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # other fields
Ajit Patil
  • 11
  • 2
0

If I do a python manage.py inspectdb the output is something like this:

class SomeModel(models.Model):
    uid = models.TextField(primary_key=True)

class SomeOtherModel(models.Model):
    uid = models.TextField()

This doesn't work though. For whatever reason, this won't work if uid is the primary key. So I change it to this:

class SomeModel(models.Model):
    uid = models.TextField()

class SomeOtherModel(models.Model):
    somemodel = models.ForeignKey(SomeModel, db_column='uid', to_field='uid')

This seems to work, but is painfully slow.

Jason Baker
  • 192,085
  • 135
  • 376
  • 510
-3

For those who actually need to generate GUIDs:

guid = hashlib.sha1(str(random.random())).hexdigest()
sth
  • 222,467
  • 53
  • 283
  • 367
Adam Nelson
  • 7,932
  • 11
  • 44
  • 64
  • 3
    Your answer has next to nothing to do with the question that was asked, please stick to answering the question instead of providing tangential info. Beyond that, however, your code is wrong since it provides a very dangerous chance of GUID collisions. A better option would be to use the built-in functions `uuid.uuid1()` or `uuid.uuid4()` – Toji Nov 15 '10 at 23:08