[Django] #21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'

369 views
Skip to first unread message

Django

unread,
Sep 5, 2013, 3:44:58 AM9/5/13
to django-...@googlegroups.com
#21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'
-------------------------------------+-------------------------------------
Reporter: kvanman@… | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 1.5
(models, ORM) | Keywords: AttributeError NoneType
Severity: Normal | attname
Triage Stage: Unreviewed | Has patch: 1
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Got an error:
AttributeError: 'NoneType' object has no attribute 'attname'

Because a model can be 'abstract = True' doesn't have a pk, but a form
(also 'abstract = True') can be used for validation 'is_valid()'. I use it
for Ajax validation of a single item in a form with multiple items.

See also ticket:17615#comment:6, request to open a new ticket, here it is.
6 month later because I moved to another system and had to install Django
again and ran into this bug again. I made a copy of the example etc.

Here is a complete example, starting with a table with some values:
{{{
CREATE TABLE test_contact (
`id` int(11) NOT NULL auto_increment,
`subject` varchar(64) NOT NULL,
`email` varchar(64) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `subject` (`subject`)
) ENGINE=InnoDB;
INSERT INTO test_contact VALUES (1,'aaa','a...@test.com');
INSERT INTO test_contact VALUES (2,'bbb','b...@test.com');
INSERT INTO test_contact VALUES (3,'ccc','c...@test.com');
}}}

python manage.py shell

{{{
import django
django.get_version()
'1.5'

from django.db import models

class ContactSubjectManager(models.Manager):
def get_query_set(self):
return Contact.objects.values('id','subject').all()

class ContactSubject(models.Model):
subject = models.CharField(max_length=64, unique=True)
objects = ContactSubjectManager()
class Meta:
abstract = True
app_label = 'test'

class ContactEmailManager(models.Manager):
def get_query_set(self):
return Contact.objects.values('id','email').all()

class ContactEmail(models.Model):
email = models.CharField(max_length=64)
objects = ContactEmailManager()
class Meta:
abstract = True
app_label = 'test'

class Contact(ContactSubject,ContactEmail):
objects = models.Manager()
class Meta:
app_label = 'test'
def __unicode__(self):
return u'%s - %s' % (self.subject, self.email)

from django import forms

class ContactSubjectForm(forms.ModelForm):
subject = forms.RegexField(
regex = r'^[ 0-9a-zA-Z()-]+$',
max_length = 30,
min_length = 3,
error_messages = {'invalid': u'Please enter a valid subject.'})
class Meta:
abstract = True
model = ContactSubject

class ContactEmailForm(forms.ModelForm):
email = forms.EmailField(
error_messages = {'invalid': u'Please enter a valid email
address.'})
class Meta:
abstract = True
model = ContactEmail

class ContactForm(ContactSubjectForm,ContactEmailForm):
class Meta:
model = Contact

f = Contact.objects.all()
f
[<Contact: aaa - a...@test.com>, <Contact: bbb - b...@test.com>, <Contact:
ccc - c...@test.com>]

data = { 'subject': 'aaa' , 'email' : 'a...@test.com' }
}}}

So far, so good, but now we ran in some problems

{{{
f = ContactForm(data)
f.is_valid()
False
f.errors
{'subject': [u'Contact with this Subject already exists.']}

data = { 'subject': 'aaa'}
f = ContactSubjectForm(data)
f.is_valid()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "./lib/python2.7/site-packages/django/forms/forms.py", line 126, in
is_valid
return self.is_bound and not bool(self.errors)
File "./lib/python2.7/site-packages/django/forms/forms.py", line 117, in
_get_errors
self.full_clean()
File ".l/lib/python2.7/site-packages/django/forms/forms.py", line 274,
in full_clean
self._post_clean()
File "./lib/python2.7/site-packages/django/forms/models.py", line 344,
in _post_clean
self.validate_unique()
File "./lib/python2.7/site-packages/django/forms/models.py", line 353,
in validate_unique
self.instance.validate_unique(exclude=exclude)
File "./lib/python2.7/site-packages/django/db/models/base.py", line 731,
in validate_unique
errors = self._perform_unique_checks(unique_checks)
File "./lib/python2.7/site-packages/django/db/models/base.py", line 823,
in _perform_unique_checks
model_class_pk = self._get_pk_val(model_class._meta)
File "./lib/python2.7/site-packages/django/db/models/base.py", line 466,
in _get_pk_val
return getattr(self, meta.pk.attname)
AttributeError: 'NoneType' object has no attribute 'attname'
}}}

The output should be:

{{{
f.is_valid()
False
f.errors
{'subject': [u'Contact subject with this Subject already exists.']}
}}}

Solution, see also ticket:17615#comment:7

In function _perform_unique_checks "lib/python2.7/site-
packages/django/db/models/base.py" remove comment on lines 817-822

{{{
# Exclude the current object from the query if we are editing
an
# instance (as opposed to creating a new one)
# Note that we need to use the pk as defined by model_class,
not
# self.pk. These can be different fields because model
inheritance
# allows single model to have effectively multiple primary
keys.
# Refs #17615.
}}}

remove code lines:

{{{
823 model_class_pk = self._get_pk_val(model_class._meta)
824 if not self._state.adding and model_class_pk is not None:
825 qs = qs.exclude(pk=model_class_pk)
}}}

add these 2 lines (same as in Django 1.4)

{{{
if not self._state.adding and self.pk is not None:
qs = qs.exclude(pk=self.pk)
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/21040>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Sep 6, 2013, 11:05:52 AM9/6/13
to django-...@googlegroups.com
#21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'
-------------------------------------+-------------------------------------
Reporter: kvanman@… | Owner: sduveen
Type: Bug | Status: assigned

Component: Database layer | Version: 1.5
(models, ORM) | Resolution:
Severity: Normal | Triage Stage:
Keywords: AttributeError | Unreviewed
NoneType attname | Needs documentation: 0
Has patch: 1 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 1 |
-------------------------------------+-------------------------------------
Changes (by sduveen):

* owner: nobody => sduveen
* needs_better_patch: => 0
* status: new => assigned
* needs_tests: => 0
* needs_docs: => 0


--
Ticket URL: <https://code.djangoproject.com/ticket/21040#comment:1>

Django

unread,
Sep 6, 2013, 11:53:27 AM9/6/13
to django-...@googlegroups.com
#21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'
-------------------------------------+-------------------------------------
Reporter: kvanman@… | Owner: sduveen
Type: Bug | Status: closed

Component: Database layer | Version: 1.5
(models, ORM) | Resolution:
Severity: Normal | worksforme
Keywords: AttributeError | Triage Stage:
NoneType attname | Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by sduveen):

* status: assigned => closed
* resolution: => worksforme


Comment:

I'm not getting the error. I have a test doing the same thing here:
https://github.com/schuyler1d/django/commit/cef85acabbdd7970b878f9c8393110757cdc56ee
(which could be pulled just to add a test to the system)

If kvanman can tweak the error to cause the issue, then maybe we can re-
open.

--
Ticket URL: <https://code.djangoproject.com/ticket/21040#comment:2>

Django

unread,
Sep 7, 2013, 7:00:06 AM9/7/13
to django-...@googlegroups.com
#21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'
-------------------------------------+-------------------------------------
Reporter: kvanman@… | Owner: sduveen
Type: Bug | Status: closed
Component: Database layer | Version: 1.5
(models, ORM) | Resolution:
Severity: Normal | worksforme
Keywords: AttributeError | Triage Stage:
NoneType attname | Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by kvanman@…):

I hope if I understand correctly did you try my example??? Your answer
doesn't make sense.

--
Ticket URL: <https://code.djangoproject.com/ticket/21040#comment:3>

Django

unread,
Sep 7, 2013, 7:02:48 AM9/7/13
to django-...@googlegroups.com
#21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'
-------------------------------------+-------------------------------------
Reporter: kvanman@… | Owner: sduveen

Type: Bug | Status: new
Component: Database layer | Version: 1.5
(models, ORM) | Resolution:
Severity: Normal | Triage Stage:
Keywords: AttributeError | Unreviewed
NoneType attname | Needs documentation: 0
Has patch: 1 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 1 |
-------------------------------------+-------------------------------------
Changes (by kvanman@…):

* status: closed => new
* resolution: worksforme =>


Comment:

please try my example ...

--
Ticket URL: <https://code.djangoproject.com/ticket/21040#comment:4>

Django

unread,
Sep 7, 2013, 2:54:38 PM9/7/13
to django-...@googlegroups.com
#21040: Bug in db/models/base.py, 'NoneType' object has no attribute 'attname'
-------------------------------------+-------------------------------------
Reporter: kvanman@… | Owner: sduveen
Type: Bug | Status: closed
Component: Database layer | Version: 1.5
(models, ORM) | Resolution: invalid

Severity: Normal | Triage Stage:
Keywords: AttributeError | Unreviewed
NoneType attname | Needs documentation: 0
Has patch: 1 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 1 |
-------------------------------------+-------------------------------------
Changes (by Koen Biermans <koen@…>):

* status: new => closed
* resolution: => invalid


Comment:

The problem is the use of a ModelForm for an abstract model.

In #19271 claudep (core developer) stated that ModelForm is not meant to
be used with abstract models. If you think this is wrong and your use case
is legitimate, you should bring this up on the django-dev mailinglist.

--
Ticket URL: <https://code.djangoproject.com/ticket/21040#comment:5>

Reply all
Reply to author
Forward
0 new messages