On Thu, Sep 15, 2011 at 09:43:57AM -0700, Tobia Conforto wrote:
> Hi all
> 
> I'm adding an XML mapping feature to Django db models.
> 
> The idea is to add as little XML mapping information as possible to existing 
> models (such as: which fields get mapped to XML, what is their XPath...) in 
> order to be able to automatically:
> 1. produce an XML representation of an object; 
> 2. parse a valid XML representation into a new object; and 
> 3. get an XSD schema of the model.
> 
> I'm well ahead. I have all three features working for some simple models. 
> But I've hit a wall with regard to object relations, or ForeignKey fields.
> 
> Apparently any subclasses of ForeignKey are completely ignored by Django at 
> runtime, even if they declare __metaclass__ = SubfieldBase
> 
> I guess they would need a special kind of metaclass, which I guess has not 
> been written yet.
> 
> Can anybody help me understand what piece is failing?
> How can I make it work?
> 
> -Tobia
> 
> 
> Here is a (non) working example:
> 
> ### test/models.py:
> 
> from django.db.models import *
> 
> # subclassing works for any simple field type, why not related fields?
> class MyForeignKey(ForeignKey):
> __metaclass__ = SubfieldBase
> 
> def __init__(self, *args, **kwargs):
> ForeignKey.__init__(self, *args, **kwargs)
> 
> class TestSub(Model):
> pass
> 
> class Test(Model):
> sub = MyForeignKey(TestSub)
> 
> ### shell:
> 
> >>> from test.models import Test, TestSub
> >>> ts = TestSub.objects.create()
> >>> t = Test.objects.create(sub=ts)
> Traceback (most recent call last):
>   ...
> AttributeError: 'Test' object has no attribute 'sub_id'
> >>>

I'd say the problem here is that when you use the SubfieldBase
metaclass, your field subclass acts as a descriptor for the field and
attaches itself to the model class. This exploits the fact that
regular field types don't do any special voodoo regarding model
instances.

With ForeignKeys, however, the situation is quite a lot different. In
this case the field attaches a RelatedDescriptor to the model which
handles the object accessible through the field's name and takes care
of storing the actual field's value in another attribute of the model
instance (its name with '_id' appended, hence sub_id in your example).

What happens with your code is that the SubfieldBase metaclass
overrides the RelatedDescriptor, so the value you pass here::

   >>> t = Test.objects.create(sub=ts)

gets stored directly in the 'sub' attribute and 'sub_id', which is
where Django expects the raw value for ForeignKeys, is not set at all.


As for what you are doing, I don't think subclassing ForeignKeys is
the way to go. Currently they defer most of the work to their target
fields, you might try to do something similar with the features you're
trying to add.

Michal

Attachment: signature.asc
Description: Digital signature

Reply via email to