Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract Models and Foreign Keys in Django

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.

like image 948
phoxley Avatar asked Sep 23 '11 17:09

phoxley


2 Answers

Maybe what you need here is a GenericForeignKey, since you don't actually know what model your ForeignKeys 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.

like image 51
Michael C. O'Connor Avatar answered Jan 01 '23 22:01

Michael C. O'Connor


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                                                                        
like image 23
rrauenza Avatar answered Jan 01 '23 23:01

rrauenza