Opened 17 years ago
Last modified 14 years ago
#10249 closed
Cannot create a consistent method resolution order (MRO) for bases FieldFile, File — at Version 4
| Reported by: | Karen Tracey | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.2-beta |
| Severity: | Keywords: | ||
| Cc: | marcelo@… | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Originally reported here: http://groups.google.com/group/django-users/browse_thread/thread/33dababaeb3b6ca7#
Easily recreatable:
Python 2.5.1 (r251:54863, Jul 31 2008, 23:17:40)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from ttt.models import FileT
>>> from django.core.files import File
>>> f = open('ttt/models.py')
>>> f.read()
"from django.db import models\n\n# Create your models here.\nclass FileT(models.Model):\n name = models.CharField(max_length=22)\n file = models.FileField(upload_to='tmp')\n\n"
>>> FileT.objects.create(name='x',file=File(f))
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/kmt/tmp/django/trunk/django/db/models/manager.py", line 99, in create
return self.get_query_set().create(**kwargs)
File "/home/kmt/tmp/django/trunk/django/db/models/query.py", line 352, in create
obj.save(force_insert=True)
File "/home/kmt/tmp/django/trunk/django/db/models/base.py", line 328, in save
self.save_base(force_insert=force_insert, force_update=force_update)
File "/home/kmt/tmp/django/trunk/django/db/models/base.py", line 388, in save_base
values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
File "/home/kmt/tmp/django/trunk/django/db/models/fields/files.py", line 184, in pre_save
file = super(FileField, self).pre_save(model_instance, add)
File "/home/kmt/tmp/django/trunk/django/db/models/fields/__init__.py", line 179, in pre_save
return getattr(model_instance, self.attname)
File "/home/kmt/tmp/django/trunk/django/db/models/fields/files.py", line 135, in __get__
(file.__class__, FieldFile), {})
TypeError: Cannot create a consistent method resolution
order (MRO) for bases FieldFile, File
>>>
Behavior was introduced in r9766, the create() works in r9765. I do not know enough about the code here to know if any fix for the other r9766-related tickets (#10121, #10179, #10196) would fix this, figured it might be worth its own ticket.
Change History (5)
comment:1 by , 17 years ago
| Cc: | added |
|---|
comment:2 by , 17 years ago
comment:3 by , 17 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:4 by , 17 years ago
| Description: | modified (diff) |
|---|---|
| milestone: | → 1.1 |
by , 17 years ago
| Attachment: | 10249.diff added |
|---|
Note:
See TracTickets
for help on using tickets.
The problem is with this code in source:django/trunk/django/db/models/fields/files.py in the FileDescriptor class (around line 130):
self.field.attr_classis going to be FieldFile in the specific case noted here (it can also be ImageFieldFile). But FieldFile is based on File, so that code is essentially trying to do:>>> class File(object): pass ... >>> class FieldFile(File): pass ... >>> class X(File, FieldFile): pass ... Traceback (most recent call last): File "<console>", line 1, in <module> TypeError: Error when calling the metaclass bases Cannot create a consistent method resolution order (MRO) for bases FieldFile, FileSpecifying File first contradicts the lookup order specified by the fact that FieldFile derives from File, and Python complains. Reversing the order works:
But I'm questioning whether this code is really the right approach to 'add the FieldFile interface' to something. Based on what's being seen in #10300 it is also having the effect of causing the FieldFile methods to be called for routines that used to get resolved via inheritance in the class being copied here, with unexpected results. That is, it isn't just adding some missing methods, but changing how some existing ones are resolved. Perhaps there is some cleaner way to just add methods, which seems to be what the comment (and possibly the order in which the bases are currently listed) implies is the intent of the code? Mucking with an object's
__class__is messing with a level of Python I'm not really comfortable with, so feedback from someone with more Python depth would be useful here.