I have a model, 'Items', which is generic enough to extend to more
specialized items, like a 'book items' model for example. This
relationship has been modelled as a one-to-one, but when listing the
detail of any given Item, I would dearly like to have the extended data
displayed too - whatever that may be. The problem is I can't figure out
how to detect that extra data without adding some indication in the
Items table as to what other table(s) to check in. Or I could check all
specialized tables, which is clunky.
Is this a common problem with a solution?
Any help would be appreciated ..
Alice
Personally, I avoid separating one2one rows into multiple tables, and
opt to adding more fields into the same table, and then just logically
"extract" whatever field the application needs. Though in ORM world,
this would be a bit difficult or perhaps unnatural way of doing it.
In django, it's easy to get values on the related one2one fields if the
related class name, its module/app name, and the field is specified at
design time:
a = items.get_object(pk=1)
a.get_myapp_itembook().book_title
It becomes tricky otherwise (I can't find an easy way). If you would
only wish to know the extra one2one model's module, this might an
alternative:
from django.core.meta import fields
rel_class_module = [o.opts.get_model_module() \
for o in Item._meta.get_all_related_objects() \
if isinstance(o.field.rel, fields.OneToOne)]
But then you would still need extra steps to get_object(pk=a.pk),
iterate the class' _meta.field to get instance of Field except
OneToOneField, then getattr() their values, ideally in a dictionary
keyed by its name (or field object). Maybe:
allfields = {}
for m in rel_class_module:
obj = m.get_object(pk=a.pk)
for f in m.Klass._meta.field:
if isinstance(f, fields.Field) and \
not isinstance(f, fields.OneToOneField):
allfields[f.name] = getattr(obj, f.name)
# or this:
#allfields[f] = getattr(obj, f.name)
Finally, iterate the dict, all without first knowing Item's related
models or their fields name:
for key,val in allfields.items():
print key,'=',val
# or if using [f] above
# print key.verbose_name,'=',val
--
dsw
python+django make everything easier than java, but I don't think there
is any nice clean way of modelling something like this.
It might be easier to have each specialized model inheriting from a
generic item class (through django), then listing each seperately or
performing a search across the multiple models ...
... or a model method like item_get_extras() that searches known
specialization models for foreign keys ...
hrm ~ no nice way of doing this it seems.
Alice
There may be some way to find out using introspection. You have the
_meta.fields list available for doing so - you could possibly look at
all non-null OneToOne fields and display the extra data in your model:
def get_all_fkey_reps(self):
from django.core.meta import fields
foreignkeys = [f for f in self._meta.fields if str(f.__class__)
== str(fields.ForeignKey)]
for key in foreignkeys:
if getattr(self, key.attname):
print repr(getattr(self, 'get_%s' % (key.name))())
This was just for debugging though - in your case you probably just
want to return the first non-null object.
-rob
Please take a look at my reply in that post. I think both topics are
awefully similar, should we simply "close" my post and discuss in here
instead?
-Roberto.
Hi Roberto,
I'm not sure the goals you are asking for are the same. What I
mentioned applied to the model only, not to the admin interface.
You should not need to compromise your model for a simpler interface -
Django is flexible enough for you to get by without having to do that.
However, using manipulators is not terribly easy. You might want to try
using some functions that extend object_detail or use multiple
manipulators in the change_stage method (which is what I did).
-rob