Reputation: 474
I am working on a django project in which I create a set of three abstract models that I will use for a variety of apps later on. The problem I am running into is that I want to connect those models via ForeignKey but django tells me that it can't assign foreignkeys to an abstract model.
My current solution is to assign foreignkeys when I instanciate the class in my other apps. However, I am writing a Manager for the abstract classes (book and pages) right now and would need to access these foreignkeys. What I am basically trying to do is to get the number of words a book has in a stateless manner, hence without storing it in a field of the page or book.
The model looks similar to this:
class Book(models.Models):
name = models.CharField(...)
author = models.CharField(...)
...
class Meta:
abstract = True
class Page(models.Models):
book = models.ForeignKey(Book)
chapter = models.CharField(...)
...
class Meta:
abstract = True
class Word(models.Models):
page = models.ForeignKey(Page)
line = models.IntegerField(...)
...
class Meta:
abstract = True
Note that this model here is just to give an example of what I am trying to do, hence whether this model (Book-Page-Word) makes sense from an implementation standpoint is not needed.
Upvotes: 10
Views: 9610
Reputation: 178
Two things:
1) The way you constructed your schema, you will need a GenericForeignKey, as already mentioned. But you must take into account that Book through Page have a many-to-many relationship with Word, while a GenericForeignKey just realizes a one-to-many. Django has nothing out-of-the-box yet for the normalized schema. What you will have to do (if you care about normalization) is to implement the intermediate (with "through" for concrete Models) yourself.
2) If you care about language processing, using a relational database (with or without Django's ORM) is not a very efficient approach, considering the resulting database size and query time after a few dozen books. Add to that the extra columns you will need to look up for your joins because of the abstract Models, and it will soon become very impractical. I think that it would be more beneficial to look into other approaches, for example storing only the aggregates and/or denormalizing (even looking into non-relational storage systems in this case), based on your queries and views.
Upvotes: 0
Reputation: 7003
How about this approach? I'm considering using it myself to delay the relationship definition until I inherit.
# This is a very very contrived (but simple) example.
def AbstractBook(AuthorModel):
class AbstractBookClass(Model):
name = CharField(max_length=10)
author = ForeignKey(AuthorModel)
class Meta:
abstract = True
return AbstractBookClass
class AbstractAuthor(Model):
name = CharField(max_length=10)
class Meta:
abstract = True
class BadAuthor(AbstractAuthor):
pass
class BadBook(AbstractBook(BadAuthor)):
pass
class GoodAuthor(AbstractAuthor):
pass
class GoodBook(AbstractBook(GoodAuthor)):
pass
Upvotes: 5
Reputation: 9890
Maybe what you need here is a GenericForeignKey
, since you don't actually know what model your ForeignKey
s will point to? That means that you'll loose some of the "type-safety" guarantees of a normal relation, but it will allow you to specify those relationships in a more general way. See https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericForeignKey
Django model inheritance is a cool thing, and nice as a shortcut for making your models DRYer, but doesn't always play nicely with the polymorphic ideas we generally have of classes.
Upvotes: 13