I am facing a really strange problem with django-tastypie. Well, this is a bit over complicated so let me start off with the tech stack of my application.
I have a comment model and two user models Student and Teacher which are derived from subclassing a base user model. Something like the following.
## Base User
class BaseUser(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
# some more common fields here
## Teacher Model
class Teacher(BaseUser):
college = models.ForeignKey(College)
## Student Model
class Student(BaseUser):
Address = models.OneToOneField(Address)
## Comment Model
class Comment(models.Model):
date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(backend.models.CustomUser)
body = models.TextField()
# Generic Relation with other models
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
user = generic.GenericForeignKey('content_type', 'object_id')
Now as you can see in my comment model i use GenericForeignKey so that a user can comment on any other model.
I have the resources defined in my tastypie api.py file as follows:
class TeacherResource(BaseModelResource):
college = fields.ToOneField(CollegeResource, 'college', full=True)
class Meta(BaseModelResource.Meta):
queryset = models.Teacher.objects.all()
resource_name = 'teacher'
def dehydrate(self, bundle):
# Add content type url
ctype = models.ContentType.objects.get_for_model(models.Teacher)
bundle.data['content_type_id'] = ctype.id
bundle.data['content_type'] = '/api/v1/contrib/contenttype/%i' % ctype.id
return bundle
class StudentResource(BaseModelResource):
class Meta(BaseModelResource.Meta):
queryset = models.Student.objects.all()
resource_name = 'student'
def dehydrate(self, bundle):
# Add content type url
ctype = models.ContentType.objects.get_for_model(\
models.ProspectiveCandidate)
bundle.data['content_type_id'] = ctype.id
bundle.data['content_type'] = '/api/v1/contrib/contenttype/%i' % ctype.id
return bundle
class CommentResource(BaseModelResource):
custom_user = fields.ToOneField(CustomUserResource,
'custom_user', full=True)
user = fields.ToOneField(ContentTypeResource, 'content_type')
class Meta(MarketingResource.Meta):
queryset = models.Comment.objects.all()
resource_name = 'comment'
always_return_data = True
filtering = {
'user' : ALL_WITH_RELATIONS,
'object_id': ALL_WITH_RELATIONS
}
def hydrate(self, bundle):
print bundle.data
bundle.obj.user = models.ContentType.objects.get_for_id(\
int(bundle.data['object_id']))
bundle.obj.object_id = int(bundle.data['object_id'])
bundle.obj.employee = bundle.request.user.custom_user
return bundle
def dehydrate(self, bundle):
if bundle.obj.date:
bundle.data['date'] = timesince.timesince(bundle.obj.date)
return bundle
All the above resources are correctly registered. The GET method for each of the resources work perfectly. I use angularjs' $resource to make calls to the tastypie's REST api. The following is a generic method that i use to send a post request to CommentResource in order to create a new commetn object.
function make_comment(service, scope){
service.save({
"user": scope.user.content_type,
"object_id": scope.user.id,
"comments": $("textarea#comment").val()
}, function(data){
// Success callback Method
scope.comments.push(data);
});
}
pretty simple eh ? Now in the above method a scope.user can either be a teacher object or a student object and the method simply uses the service to make a POST request with the given data to:
http://127.0.0.1:8000/api/v1/comment
The problem is that when the scope.user is a student object and i call the above method i get a 201 created response but when it is a teacher object it gives me a 404 Not Found error.
The data passed in while using student and teacher objects is pretty similar(which is as follows):
data = {'user': '/api/v1/contrib/contenttype/15', 'object_id': '16', 'comments': 'sadfsadfsadfasdf'} response = [19/Mar/2013 18:08:47] "POST /api/v1/comment HTTP/1.1" 201 741
data = {'user': '/api/v1/contrib/contenttype/14', 'object_id': '62', 'comments': 'test comment'} response = [19/Mar/2013 18:09:44] "POST /marketing/api/v1/comment HTTP/1.1" 404 3211
I am not able to understand why using the same code would work for one model and not for the other ? Could you please give me some pointers. Thanks.
So I was using a custom http error tracking middleware which will send the response as 404 Not Found and when I switched it off i get the following error now.
ContentType matching query does not exist
I looked up the database and the contenttype with id 14 is the Teacher and it is there in the database.
The problem lies here in the hydrate method:
def hydrate(self, bundle):
print bundle.data
bundle.obj.user = models.ContentType.objects.get_for_id(\
int(bundle.data['object_id'])) // this should be content_type_id
bundle.obj.object_id = int(bundle.data['object_id'])
bundle.obj.employee = bundle.request.user.custom_user
return bundle
so changed comment function to pass in content_type_id and changed hydrate method to
def hydrate(self, bundle):
print bundle.data
bundle.obj.user = models.ContentType.objects.get_for_id(\
int(bundle.data['content_type_id'])) // this was friggin stupid.
bundle.obj.object_id = int(bundle.data['object_id'])
bundle.obj.employee = bundle.request.user.custom_user
return bundle