{{{
<function make_generic_foreign_order_accessors at 0x7f5444873488>:
(models.E022) <function make_generic_foreign_order_accessors at
0x7f5444873488> contains a lazy reference to testac.abstractmaster, but
app 'testac' doesn't provide model 'abstractmaster'.
testac.DetailTest.relatedMasterModel: (fields.E307) The field
testac.DetailTest.relatedMasterModel was declared with a lazy reference to
'testac.abstractmaster', but app 'testac' doesn't provide model
'abstractmaster'.
}}}
**models.py**
{{{
from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey,
GenericRelation
from django.contrib.contenttypes.models import ContentType
class AbstractMaster (models.Model):
class Meta: abstract=True
detailModel_type = models.ForeignKey(ContentType, blank=True,
null=True)
detailModel_id = models.PositiveIntegerField(blank=True, null=True)
detail_Model = GenericForeignKey('detailModel_type', 'detailModel_id')
class AbstractDetail (models.Model):
class Meta: abstract=True
masterModel_type = models.ForeignKey(ContentType, blank=True,
null=True)
masterModel_id = models.PositiveIntegerField(blank=True, null=True)
master_Model = GenericForeignKey('masterModel_type', 'masterModel_id')
relatedMasterModel = GenericRelation(AbstractMaster,
object_id_field='detailModel_id', content_type_field='detailModel_id',
related_query_name='%(app_label)s_%(class)s_detail_model')
class MasterTest (AbstractMaster):
pass
class DetailTest (AbstractDetail):
pass
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27460>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* cc: Alex Hill (added)
* component: Uncategorized => Core (Other)
Comment:
Alex, was this an oversight in 2ff7ef15b0a1d41e3f121e96cb72a383863046c0?
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:1>
Comment (by Alex Hill):
I'm pretty sure this is just a more explicit failure of something that
didn't work before. You can create the models as described, but see it
blow up in 1.9 in the sample below when you actually try to use it.
I might be thinking about this wrong, but what would a GenericRelation to
an abstract model mean? Which model would queries on the field yield
instances of?
Wolfgang - can you provide an example of how you were successfully using
this in 1.9?
{{{
>>> from ag.models import MasterTest, DetailTest
>>> mt = MasterTest.objects.create()
>>> dt = DetailTest.objects.create()
>>> mt.detail_Model = dt
>>> mt.save()
>>> dt.master_Model = mt
>>> dt.save()
>>>
>>> dt.relatedMasterModel.all()
Traceback (most recent call last):
File "/home/alexh/djexperiments/env/lib/python3.5/site-
packages/django/core/management/commands/shell.py", line 69, in handle
self.run_shell(shell=options['interface'])
File "/home/alexh/djexperiments/env/lib/python3.5/site-
packages/django/core/management/commands/shell.py", line 61, in run_shell
raise ImportError
ImportError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/alexh/djexperiments/env/lib/python3.5/site-
packages/django/db/models/fields/related_descriptors.py", line 468, in
__get__
return self.related_manager_cls(instance)
File "/home/alexh/djexperiments/env/lib/python3.5/site-
packages/django/utils/functional.py", line 33, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/home/alexh/djexperiments/env/lib/python3.5/site-
packages/django/contrib/contenttypes/fields.py", line 448, in
related_manager_cls
self.rel.model._default_manager.__class__,
AttributeError: type object 'AbstractMaster' has no attribute
'_default_manager'
>>>
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:2>
Comment (by Wolfgang Grim):
Hmm I also don't get it to run now - But I can explain what I want to
achieve:
models.py
{{{
from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey,
GenericRelation
from django.contrib.contenttypes.models import ContentType
class AbstractMaster (models.Model):
class Meta: abstract=True
detailModel_type = models.ForeignKey(ContentType, blank=True,
null=True)
detailModel_id = models.PositiveIntegerField(blank=True, null=True)
detail_Model = GenericForeignKey('detailModel_type', 'detailModel_id')
class AbstractDetail (models.Model):
class Meta: abstract=True
name = models.CharField (max_length=255, null=True)
masterModel_type = models.ForeignKey(ContentType, blank=True,
null=True)
masterModel_id = models.PositiveIntegerField(blank=True, null=True)
master_Model = GenericForeignKey('masterModel_type', 'masterModel_id')
relatedMasterModel = GenericRelation(AbstractMaster,
object_id_field='detailModel_id', content_type_field='detailModel_id',
related_query_name='%(app_label)s_%(class)s_detail_model')
class MasterTest (AbstractMaster):
pass
class DetailTest (AbstractDetail):
pass
}}}
python manage.py shell
{{{
from testac.models import MasterTest, DetailTest
mt = MasterTest.objects.create()
dt = DetailTest.objects.create(name="Test")
mt.detail_Model = dt
mt.save()
dt.master_Model = mt
dt.save()
mt.detail_Model.name
# Out[8]: 'Test' (So this is working)
MasterTest.objects.filter(detail_Model__name="Test")
# Throws: FieldError: Field 'detail_Model' does not generate an automatic
reverse relation and therefore cannot be used for reverse querying. If it
is a GenericForeignKey, consider adding a GenericRelation.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:3>
Comment (by Tim Graham):
If the use case is invalid, perhaps the error message about " app 'testac'
doesn't provide model 'abstractmaster'" could be improved with an
explanation about abstract models?
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:4>
Comment (by Alex Hill):
Hi Tim,
The message when you try to declare a normal relation to an abstract model
is this:
{{{
ag.DetailTest.something: (fields.E300) Field defines a relation with model
'AbstractSomething', which is either not installed, or is abstract.
}}}
I'll look at how we can catch the GenericRelation case in the same branch,
because that's much nicer.
Wolfgang: the trend in Django is to alert the user to problems earlier
rather than later, and I'm quite sure that's what's happening here. There
hasn't actually been any change in functionality since 1.9.
When you do `MasterTest.objects.filter(detail_Model__name="Test")`, Django
doesn't know which table to look for a matching "name" field in, because
the relation is generic and that information is stored in the database. It
would technically be possible to implement this, and return a
heterogeneous collection of objects that inherit from the abstract model,
but the code would be messy, it would be completely new ground for the
Django ORM, and for such a corner case I just don't think it would be
accepted.
There are third-party libraries that provide more polymorphism in Django,
and I'd recommend looking into those to see if they meet your needs. Here
are a couple:
https://django-polymorphic.readthedocs.io/en/stable/
https://django-model-
utils.readthedocs.io/en/latest/managers.html#inheritancemanager
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:5>
* owner: nobody => Alex Hill
* status: new => assigned
Comment:
Tim: should I accept this and change its description to indicate that the
error message needs improvement, or close it and create a new ticket?
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:6>
Comment (by Wolfgang Grim):
Hello! At least the following should work right?
{{{
from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey,
GenericRelation
from django.contrib.contenttypes.models import ContentType
class AbstractDetail (models.Model):
class Meta: abstract=True
relatedTrackModel = GenericRelation("TrackDetail",
object_id_field='detailModel_id', content_type_field='detailModel_id',
related_query_name='%(app_label)s_%(class)s_detail_model')
class TrackDetail (models.Model):
detailModel_type = models.ForeignKey(ContentType, blank=True,
null=True)
detailModel_id = models.PositiveIntegerField(blank=True, null=True)
detail_Model = GenericForeignKey('detailModel_type', 'detailModel_id')
added = models.DateTimeField(null=True)
class DetailTest (AbstractDetail):
name = models.CharField(max_length=200, null=True)
pass
}}}
shell:
{{{
from testac.models import DetailTest, TrackDetail
from django.utils import timezone
dt = DetailTest.objects.create(name="name1")
track = TrackDetail.objects.create()
track.detail_Model=dt
track.added = timezone.now()
x =
TrackDetail.objects.filter(testac_detailtest_detail_model__name="name")
FieldError: Cannot resolve keyword 'testac_detailtest_detail_model' into
field. Choices are: %(app_label)s_%(class)s_detail_model, added,
detailModel_id, detailModel_type, detailModel_type_id, detail_Model, id
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:7>
Comment (by Alex Hill):
That could potentially work, I think.
Does it work in 1.9, or is this a new feature?
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:8>
Comment (by Wolfgang Grim):
It doesn't work neither in 1.9 nor in 1.10 I receive
{{{
FieldError: Cannot resolve keyword 'testac_detailtest_detail_model' into
field. Choices are: %(app_label)s_%(class)s_detail_model, added,
detailModel_id, detailModel_type, detailModel_type_id, detail_Model, id
}}}
using dt.relatedTrackModel() I get an empty Queryset
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:9>
* type: Bug => New feature
* component: Core (Other) => Database layer (models, ORM)
* stage: Unreviewed => Accepted
Comment:
Tentatively accepting and retitling based on a skim of the issue.
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:10>
* owner: Alex Hill => (none)
* status: assigned => new
--
Ticket URL: <https://code.djangoproject.com/ticket/27460#comment:11>