Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #9649 -- Better error handling in model creation.

Previously, you could explicitly assign None to a non-null ForeignKey
(or other) field when creating the model (Child(parent=None), etc). We
now throw an exception when you do that, which matches the behaviour
when you assign None to the attribute after creation.

Thanks to ales.zoulek@gmail.com and ondrej.kohout@gmail.com for some
analysis of this problem.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9983 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 53da1e47942f22a56e761d786ba89d05ca55a224 1 parent b5d4a8a
Malcolm Tredinnick authored March 06, 2009
13  django/db/models/base.py
@@ -224,12 +224,13 @@ def __init__(self, *args, **kwargs):
224 224
         # keywords, or default.
225 225
 
226 226
         for field in fields_iter:
227  
-            rel_obj = None
  227
+            is_related_object = False
228 228
             if kwargs:
229 229
                 if isinstance(field.rel, ManyToOneRel):
230 230
                     try:
231 231
                         # Assume object instance was passed in.
232 232
                         rel_obj = kwargs.pop(field.name)
  233
+                        is_related_object = True
233 234
                     except KeyError:
234 235
                         try:
235 236
                             # Object instance wasn't passed in -- must be an ID.
@@ -245,11 +246,11 @@ def __init__(self, *args, **kwargs):
245 246
                     val = kwargs.pop(field.attname, field.get_default())
246 247
             else:
247 248
                 val = field.get_default()
248  
-            # If we got passed a related instance, set it using the field.name
249  
-            # instead of field.attname (e.g. "user" instead of "user_id") so
250  
-            # that the object gets properly cached (and type checked) by the
251  
-            # RelatedObjectDescriptor.
252  
-            if rel_obj:
  249
+            if is_related_object:
  250
+                # If we are passed a related instance, set it using the
  251
+                # field.name instead of field.attname (e.g. "user" instead of
  252
+                # "user_id") so that the object gets properly cached (and type
  253
+                # checked) by the RelatedObjectDescriptor.
253 254
                 setattr(self, field.name, rel_obj)
254 255
             else:
255 256
                 setattr(self, field.attname, val)
13  tests/regressiontests/many_to_one_regress/models.py
... ...
@@ -1,5 +1,5 @@
1 1
 """
2  
-Regression tests for a few FK bugs: #1578, #6886
  2
+Regression tests for a few ForeignKey bugs.
3 3
 """
4 4
 
5 5
 from django.db import models
@@ -106,6 +106,17 @@ def __unicode__(self):
106 106
     ...
107 107
 ValueError: Cannot assign "<First: First object>": "Child.parent" must be a "Parent" instance.
108 108
 
  109
+# Nor can you explicitly assign None to Child.parent during object creation
  110
+# (regression for #9649).
  111
+>>> Child(name='xyzzy', parent=None)
  112
+Traceback (most recent call last):
  113
+    ...
  114
+ValueError: Cannot assign None: "Child.parent" does not allow null values.
  115
+>>> Child.objects.create(name='xyzzy', parent=None)
  116
+Traceback (most recent call last):
  117
+    ...
  118
+ValueError: Cannot assign None: "Child.parent" does not allow null values.
  119
+
109 120
 # Creation using keyword argument should cache the related object.
110 121
 >>> p = Parent.objects.get(name="Parent")
111 122
 >>> c = Child(parent=p)

0 notes on commit 53da1e4

Please sign in to comment.
Something went wrong with that request. Please try again.