django-polymorphic
django-polymorphic copied to clipboard
How to use abstract base model classes with intermediate abstract classes
Problem (help wanted) - not sure how to change the label to help wanted
I am trying to understand how to query an abstract base class/model via a unique model field (guaranteed unique by each end concrete model sharing the same unique_together
clause(s) ). I changed the highest Parent class to the PolymorphicModel. I migrated the database using a migration written by django, then modified by me, and then migrated, and see the successful database (both django_content_types and the extra column on the concrete models).
Environment
- Django-polymorphic version: current - 545bf7d4
- Django version: 2.1
- Python version: 3.5 and 3.6
- Other libraries used, if any: none to my knowledge that involve the model classes outside of native django
Code examples
// models.py
class Asset(PolymorphicModel):
asset_id = models.CharField(max_length=100, editable=False) # argua3y4tv9yqawnqv29…
asset_name = models.CharField(max_length=200, editable=False) # 10101
account = models.ForeignKey(Account, on_delete=models.CASCADE)
class Meta(object):
abstract = True
class B(Asset): # intermediate abstract class
pass
class Meta(object):
abstract = True
class C(B):
unique_feature = models.CharField(max_length=200)
class Meta(object):
unique_together = (('asset_id', 'account'))
class D(B):
cake = models.CharField(max_length=200)
class Meta(object):
unique_together = (('asset_id', 'account'))
// urls.py
url(r'^accounts/(?P<slug>[a-zA-Z]+)/assets/(?P<assetName>[a-zA-Z0-9]+)',
AssetsViewSet.as_view({'get': 'retrieve'})),
// views.py (from a DRF viewset)
class AssetsViewSet(viewsets.ModelViewSet):
serializer_class = AssetSerializer
permission_classes = (permissions.IsAuthenticated, IsOrganizationMember,)
def retrieve(self, request, slug=None, assetName=None):
/regardless if I filter by the asset's account foregin key
queryset = Asset.objects.filter(asset_name=assetName).select_subclasses()
This gives me the error in the browser:
AttributeError at /api/v1/accounts/FSL/assets/10101 Manager isn't available; Asset is abstract
If I remove the abstract class definition on the parent class (Asset), then the django checker during compile errors for each of the concrete classes:
app.C: (models.E016) 'unique_together' refers to field 'account' which is not local to model 'C'.
HINT: This issue may be caused by multi-table inheritance.
app.C: (models.E016) 'unique_together' refers to field 'asset_id' which is not local to model 'C'.
HINT: This issue may be caused by multi-table inheritance.
I am unsure how to go about keeping the database structure of what I have (Abstract tree with many intermediate abstract models and some concrete models and to be able to query against the highest [grand]Parent abstract base class.
unique_together
is enforced at the database level, so I don't think it's possible to have the constraint set on the inherited models of a non-abstract parent. Perhaps you can override the validate_unique
method on the child models instead?
Thanks @mumumumu , I thought my uniqueness is currently working, maybe through the validations already, but I think the uniqueness is irrespective o trying to get the polymorphism to work.
I don't think you can have abstract base classes with django-polymorphic tho. Generally, the superclass has a column describing the subclass for each row (and additional SQL is emitted base on that).
If your base class is abstract, there's no table for that, so I don't see how polymorphic could figure out subclasses.