Generic Foreign Keys and other basic tools for Django-Tastypie
NOTE: tastypie-generic has been integrated into toastdriven/django-tastypie, so this repo is DEPRECATED.
Run pip install tastypie-generic
and add tastypie_generic
to your INSTALLED_APPS
.
Generic foreign keys can be plugged-in and used much as standard ForeignKeys, with the exception being that the to field takes in a dictionary, mapping models to resources, rather than a resource
GenericForeignKeyField(to, attribute[, **kwargs]):
- to: a dictionary mapping models to resources (e.g
{ User: UserResource, Event: EventResource }
) - attribute: the name of the foreign key on the model
- **kwargs: the standard kwargs from fields.ForeignKey
Often, you want to have a resource that an owner-user can edit, but anyone can view. That functionality is in UserAuthorization
UserAuthorization(attribute):
- attribute the attribute of the user who can edit the resource (e.g.
created_by
).
Imagine I'm building an app where users can follow people or events. We keep track of a follow object which has created_by
: the user following and content_object
: the object followed. It also has notes
, just for fun. The owner of a Follow (i.e. the User specified by created_by
) can edit it, and anyone can view any follow.
models.py:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
class Follow(models.Model):
created_by = models.ForeignKey(User, related_name="follows")
content_type = models.ForeignKey(ContentType, related_name="follows")
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
notes = models.TextField()
api/resources.py:
from tastypie import fields
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.resources import Resource, ModelResource
from ..models import Follow
from tastypie_generic.authorization import UserAuthorization
from tastypie_generic.fields import GenericForeignKeyField
from django.contrib.auth.models import User
from myapp.models import Event
from myapp.api.resources import UserResource, EventResource
class FollowResource(ModelResource):
created_by = fields.ForeignKey(UserResource, 'created_by')
content_object = GenericForeignKeyField({
User: UserResource,
Event: EventResource,
}, 'content_object')
def obj_create(self, bundle, request, **kwargs):
return super(FollowResource, self).obj_create(bundle, request, created_by=request.user)
def obj_update(self, bundle, request, **kwargs):
return super(FollowResource, self).obj_update(bundle, request, created_by=request.user)
class Meta:
queryset = Follow.objects.all().select_related()
allowed_methods = ['get', 'put', 'post', 'delete']
excludes = ['object_id']
authorization = UserAuthorization('created_by')
A huge thanks to David Hatch whose fork inspired the GenericForeignKeyField code.
Also to the django-tastypie team for continuing to work on an awesome piece of software, and particularly to Josh Bohde for answering my questions.