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
signature.asc
Description: Digital signature