1 | """To recreate the error, just start an app and drop in this file.
|
---|
2 | Pull up the admin interface. And add a Book. You can go ahead and add
|
---|
3 | one or more Authors at the same time. Save your changes.
|
---|
4 |
|
---|
5 | This should work with no errors. The error occurs when you save a Book
|
---|
6 | object in the Admin interface that has one or more Authors assigned to it.
|
---|
7 |
|
---|
8 | That is, after creating a Book with one or more Authors and saving it, go back
|
---|
9 | and edit that Book again in the admin interface. Don't have to change
|
---|
10 | anything, just click Save and this is the error that is generated:
|
---|
11 |
|
---|
12 |
|
---|
13 | KeyError at /admin/uuid_test/book/6b31461e-ffa2-11dd-be8a-0019dbb65276/
|
---|
14 |
|
---|
15 | None
|
---|
16 |
|
---|
17 | Request Method: POST
|
---|
18 | Request URL: http://localhost:8000/admin/uuid_test/book/6b31461e-ffa2-11dd-be8a-0019dbb65276/
|
---|
19 | Exception Type: KeyError
|
---|
20 | Exception Value: None
|
---|
21 |
|
---|
22 | Exception Location: /usr/local/lib/python2.5/site-packages/django/forms/models.py in save_existing_objects, line 411
|
---|
23 | Python Executable: /usr/bin/python
|
---|
24 | Python Version: 2.5.2
|
---|
25 | Python Path: [...]
|
---|
26 | Server time: Fri, 20 Feb 2009 17:03:31 -0600
|
---|
27 | """
|
---|
28 | from django.db import models
|
---|
29 | from django.db.models import CharField
|
---|
30 | from django.contrib import admin
|
---|
31 | try:
|
---|
32 | import uuid
|
---|
33 | except ImportError:
|
---|
34 | from django_extensions.utils import uuid
|
---|
35 |
|
---|
36 | # UUIDVersionError and UUIDField are taken directly from the django-extensions
|
---|
37 | # project with no alterations. I bundled them in this little test case
|
---|
38 | # so you wouldn't have to install django-extensions just to run the test.
|
---|
39 | class UUIDVersionError(Exception):
|
---|
40 | pass
|
---|
41 |
|
---|
42 | class UUIDField(CharField):
|
---|
43 | """ UUIDField
|
---|
44 |
|
---|
45 | By default uses UUID version 1 (generate from host ID, sequence number and current time)
|
---|
46 |
|
---|
47 | The field support all uuid versions which are natively supported by the uuid python module.
|
---|
48 | For more information see: http://docs.python.org/lib/module-uuid.html
|
---|
49 | """
|
---|
50 |
|
---|
51 | def __init__(self, verbose_name=None, name=None, auto=True, version=1, node=None, clock_seq=None, namespace=None, **kwargs):
|
---|
52 | kwargs['max_length'] = 36
|
---|
53 | if auto:
|
---|
54 | kwargs['blank'] = True
|
---|
55 | kwargs.setdefault('editable', False)
|
---|
56 | self.auto = auto
|
---|
57 | self.version = version
|
---|
58 | if version==1:
|
---|
59 | self.node, self.clock_seq = node, clock_seq
|
---|
60 | elif version==3 or version==5:
|
---|
61 | self.namespace, self.name = namespace, name
|
---|
62 | CharField.__init__(self, verbose_name, name, **kwargs)
|
---|
63 |
|
---|
64 | def get_internal_type(self):
|
---|
65 | return CharField.__name__
|
---|
66 |
|
---|
67 | def create_uuid(self):
|
---|
68 | if not self.version or self.version==4:
|
---|
69 | return uuid.uuid4()
|
---|
70 | elif self.version==1:
|
---|
71 | return uuid.uuid1(self.node, self.clock_seq)
|
---|
72 | elif self.version==2:
|
---|
73 | raise UUIDVersionError("UUID version 2 is not supported.")
|
---|
74 | elif self.version==3:
|
---|
75 | return uuid.uuid3(self.namespace, self.name)
|
---|
76 | elif self.version==5:
|
---|
77 | return uuid.uuid5(self.namespace, self.name)
|
---|
78 | else:
|
---|
79 | raise UUIDVersionError("UUID version %s is not valid." % self.version)
|
---|
80 |
|
---|
81 | def pre_save(self, model_instance, add):
|
---|
82 | if self.auto and add:
|
---|
83 | value = unicode(self.create_uuid())
|
---|
84 | setattr(model_instance, self.attname, value)
|
---|
85 | return value
|
---|
86 | else:
|
---|
87 | value = super(UUIDField, self).pre_save(model_instance, add)
|
---|
88 | if self.auto and not value:
|
---|
89 | value = unicode(self.create_uuid())
|
---|
90 | setattr(model_instance, self.attname, value)
|
---|
91 | return value
|
---|
92 |
|
---|
93 |
|
---|
94 | class Book(models.Model):
|
---|
95 | id = UUIDField(primary_key=True, auto_created=True)
|
---|
96 | title = models.CharField(max_length=128)
|
---|
97 | def __unicode__(self):
|
---|
98 | return unicode(self.title)
|
---|
99 |
|
---|
100 | class Author(models.Model):
|
---|
101 | id = UUIDField(primary_key=True, auto_created=True)
|
---|
102 | book = models.ForeignKey(Book)
|
---|
103 | name = models.CharField(max_length=128)
|
---|
104 | def __unicode(self):
|
---|
105 | return unicode(self.name)
|
---|
106 |
|
---|
107 |
|
---|
108 | class AuthorInlineAdmin(admin.TabularInline):
|
---|
109 | model=Author
|
---|
110 |
|
---|
111 | class BookAdmin(admin.ModelAdmin):
|
---|
112 | inlines = (AuthorInlineAdmin, )
|
---|
113 | admin.site.register(Book, BookAdmin)
|
---|