Skip to main content
Help the Python Software Foundation raise $60,000 USD by December 31st!  Building the PSF Q4 Fundraiser

Deferred foreign keys for Django

Project description


django-dfk implements deferred foreign keys for Django. Deferred foreign keys are conceptually similar to generic foreign keys, except that they are resolved to a real foreign key at runtime, and cause proper foreign keys to be created in the database.

This package allows you to do two things:

* Declare that a model's foreign key field is 'deferrable', and should be repointed later
* Repoint an existing model's foreign key fields, even if that model is not django-dfk aware.

You should perform the latter with caution - consider it a similar process to monkey-patching!

This package is alpha software, and is not feature-complete. See the TODO section for what’s on the list.


Install django-dfk using your preferred Python package manager. Use of virtualenv is also recommended:

pip install django-dfk


Pointing a single foreign key

Let’s say you want to reinvent the wheel, and develop a commenting app. Your comment model might look like this, in mycomments.models:

from dfk import DeferredForeignKey

class Comment(models.Model):
    commenter = models.ForeignKey('auth.User')
    content = DeferredForeignKey()
    body = models.TextField()

Now, you come to integrate this application with your blog system (which, as you’re keen on wheel reinvention, you have also written yourself). Here’s blog/

from dfk import point
from mycomments.models import Comment

class BlogPost(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField()
    body = models.TextField()

point(Comment, 'content', BlogPost)

The call to point will replace the DeferredForeignKey on Comment with a foreign key to BlogPost.

Pointing many foreign keys at once

When writing models that use deferred foreign keys, you may need to declare that a number should point to the same ‘kind’ of object. Let’s say you had wild scope creep, and your commenting app needed the ability to associate images with a blog post. So you edit your comment app’s so it looks like this:

from dfk import DeferredForeignKey

class Comment(models.Model):
    commenter = models.ForeignKey('auth.User')
    content = DeferredForeignKey(name='Content')
    body = models.TextField()

class Image(models.Model):
    image = models.ImageField()
    content = DeferredForeignKey(name='Content')

This expresses that both comments and images need to point to the same kind of model. This is accomplished with the point_named function:

from dfk import point_named
point_named('blog', 'Content', BlogPost)

Now, all DeferredForeignKey instances in the blog app which are called Content will be replaced by real foreign keys to BlogPost.

Arguments to the generated foreign keys

When declaring a deferred foreign key, you may specify additional keyword arguments. Aside from name, this will be passed on verbatim to the final foreign key.

It is also possible to pass arbitrary keyword arguments in calls to point or point_named. These will also be passed to the final foreign key. Where arguments are present in both the DFK definition and in the point/point_named call, arguments from the latter will take precedence.

Model inheritance

Model inheritance should Just Work. It’s possible to have DeferredForeignKey instances on subclasses and base classes. The only thing to be aware of is that repointing a dfk on a subclass where the key is actually defined on a non-abstract base class is illegal, and will raise a TypeError.

Cleaning object caches

Pointing or repointing foreign keys requires that related object caches are repopulated as relationships will have changed and things like filtering on related objects are likely to fail.

By default object caches are cleaned after each point or repoint. For apps with many DeferredForeignKey instances involving the same model it may be more efficient to clean the caches once, after all pointing and repointing has finished. To enable this pass clean_caches=False to point or repoint and then manually call clean_object_caches as required:

from dfk import point
from dfk import clean_object_caches
from mycomments.models import Comment

class BlogPost(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField()
    body = models.TextField()

point(Comment, 'content', BlogPost, clean_caches=False)
clean_object_caches(Comment, BlogPost)


Thanks to ISM Fantasy Games Ltd. for sponsoring this package.


Make cache cleaning optional, and fix some PEP8 compliance issues. Thanks to Mark Hughes (


Fix a problem where repointing a deferred foreign key defined on a non-abstract base class through a subclass would result in a new field being added to the local_fields of the subclass, shadowing the one on the base class. It is now illegal to do this; dfks on base classes should be pointed using the base class itself.


Fix a problem where related object caches on models’ _meta Options classes were not being repopulated on a repoint. This led to problems where filtering on a parent model related to a child using a deferred foreign key could fail if the dfk was (re)pointed after the initial phase of model loading had already taken place.


  • Include a to ensure docs are packaged.


  • Fix packaging error


  • Fix an issue when repointing foreign keys on model classes with custom fields which use the django.db.models.SubfieldBase metaclass
  • Fix an issue migrating from Django 1.2 to 1.3.


  • Initial version

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for django-dfk, version 0.0.7
Filename, size File type Python version Upload date Hashes
Filename, size django-dfk-0.0.7.tar.gz (7.9 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page