I am using Django 1.4.3 and TastyPie 0.9.11.
I have the following two django models:
class Event(models.Model):
organizer = models.ForeignKey(User, related_name='Organizador')
store = models.ForeignKey(Store, related_name='Tienda')
name = models.CharField('Titulo', max_length=50)
event_time = models.DateTimeField('Fecha y Hora del Evento')
creation_date = models.DateTimeField('Fecha de Creación', auto_now_add=True)
requires_confirmation = models.BooleanField('Require Confirmación')
class Meta:
verbose_name = "Encuentro"
verbose_name_plural = "Encuentros"
class EventInvitees(models.Model):
event = models.ForeignKey(Event, related_name='invitees')
invitee = models.ForeignKey(User, verbose_name='Invitado')
confirmed = models.BooleanField('Confirmado')
confirmation_date = models.DateTimeField('Fecha de Confirmación', null=True, auto_now=True)
class Meta:
verbose_name = "Invitados"
verbose_name_plural = "Invitados"
Then I have the following API Resources:
class EventInviteesResource(ModelResource):
user = fields.ForeignKey(UserResource, 'invitee', full=True)
event = fields.ForeignKey('bbservices.api.EventResource', 'event')
class Meta:
queryset = EventInvitees.objects.all()
authentication = ApiKeyAuthentication()
authorization = Authorization()
class EventResource(ModelResource):
invitees = fields.ToManyField('bbservices.api.EventInviteesResource', 'invitees', full=True)
store = fields.ForeignKey(StoreResource, 'store', full=True)
class Meta:
#default_format = 'application/json'
queryset = Event.objects.all()
fields = ['organizer_id', 'store', 'name', 'event_time', 'requires_confirmation']
include_resource_uri = False
#list_allowed_methods = ['get', 'post']
authentication = ApiKeyAuthentication()
authorization = Authorization()
filtering = {
#'user': ALL_WITH_RELATIONS
'event_time': ['exact', 'range', 'gt', 'gte', 'lt', 'lte'],
}
def dehydrate_event_time(self, bundle):
return bundle.data['event_time']
def obj_create(self, bundle, request=None, **kwargs):
return super(EventResource, self).obj_create(bundle, request, organizer_id=request.user.pk, store_id=bundle.data['store_id'])
As you can see, I have set up a "ToManyField" relation ship in order to have Event Invitees to show up in GET lists of the Events resource. This works Correctly. Please note that there is also an FK relationship to a "store" and this also works.
The error comes when POSTing the following to "EventInviteesResource" to create and EventInvitee:
POST http://X.X.X.X:8000/api/v1/eventinvitees/?username=user&api_key=XXXXXXX
{
"event" : {"pk" : 30},
"invitee" : 2,
"confirmed" : true
}
The error returned is:
"The 'invitees' field has no data and doesn't allow a null value."
Note that "invitees" does NOT exist in the "EventInviteesResource" but instead in the "parent" resource "EventResource". So I dont understand how this can even be an error. If I comment out the this line:
invitees = fields.ToManyField('bbservices.api.EventInviteesResource', 'invitees', full=True)
the resource "EventResource" the "invitees" error goes away and the error becomes:
{"error_message": "", "traceback": "Traceback (most recent call last):\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 192, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 397, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 427, in dispatch\n response = method(request, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1165, in post_list\n updated_bundle = self.obj_create(bundle, request=request, **self.remove_api_resource_names(kwargs))\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1774, in obj_create\n bundle = self.full_hydrate(bundle)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 698, in full_hydrate\n value = field_object.hydrate(bundle)\n\n File \"/Library/Python/2.7/site-packages/tastypie/fields.py\", line 636, in hydrate\n value = super(ToOneField, self).hydrate(bundle)\n\n File \"/Library/Python/2.7/site-packages/tastypie/fields.py\", line 154, in hydrate\n elif self.attribute and getattr(bundle.obj, self.attribute, None):\n\n File \"/Library/Python/2.7/site-packages/django/db/models/fields/related.py\", line 343, in __get__\n raise self.field.rel.to.DoesNotExist\n\nDoesNotExist\n"}
If I try to POST this:
{
"store_id" : 1,
"name" : "With Invitees",
"event_time" : "2013-02-06T18:30-3:00",
"requires_confirmation" : true,
"invitees" : [
{
"invitee": {"pk" : 1}
}
]
}
to the resource EventResource, with the 'invitees' relationship intact, the error is:
{"error_message": "int() argument must be a string or a number, not 'dict'", "traceback": "Traceback (most recent call last):\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 192, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 397, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 427, in dispatch\n response = method(request, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1165, in post_list\n updated_bundle = self.obj_create(bundle, request=request, **self.remove_api_resource_names(kwargs))\n\n File \"/Users/jleidigh/Documents/Starbucks - In Office/trunk/backend/bbservices/api.py\", line 234, in obj_create\n return super(EventResource, self).obj_create(bundle, request, organizer_id=request.user.pk, store_id=bundle.data['store_id'])\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1783, in obj_create\n m2m_bundle = self.hydrate_m2m(bundle)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 743, in hydrate_m2m\n bundle.data[field_name] = field_object.hydrate_m2m(bundle)\n\n File \"/Library/Python/2.7/site-packages/tastypie/fields.py\", line 742, in hydrate_m2m\n m2m_hydrated.append(self.build_related_resource(value, **kwargs))\n\n File \"/Library/Python/2.7/site-packages/tastypie/fields.py\", line 593, in build_related_resource\n return self.resource_from_data(self.fk_resource, value, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/fields.py\", line 548, in resource_from_data\n return fk_resource.obj_update(fk_bundle, **data)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1814, in obj_update\n bundle.obj = self.obj_get(request, **lookup_kwargs)\n\n File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1752, in obj_get\n base_object_list = self.get_object_list(request).filter(**kwargs)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/query.py\", line 624, in filter\n return self._filter_or_exclude(False, *args, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/query.py\", line 642, in _filter_or_exclude\n clone.query.add_q(Q(*args, **kwargs))\n\n File \"/Library/Python/2.7/site-packages/django/db/models/sql/query.py\", line 1250, in add_q\n can_reuse=used_aliases, force_having=force_having)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/sql/query.py\", line 1185, in add_filter\n connector)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/sql/where.py\", line 69, in add\n value = obj.prepare(lookup_type, value)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/sql/where.py\", line 320, in prepare\n return self.field.get_prep_lookup(lookup_type, value)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/fields/related.py\", line 137, in get_prep_lookup\n return self._pk_trace(value, 'get_prep_lookup', lookup_type)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/fields/related.py\", line 210, in _pk_trace\n v = getattr(field, prep_func)(lookup_type, v, **kwargs)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/fields/__init__.py\", line 310, in get_prep_lookup\n return self.get_prep_value(value)\n\n File \"/Library/Python/2.7/site-packages/django/db/models/fields/__init__.py\", line 537, in get_prep_value\n return int(value)\n\nTypeError: int() argument must be a string or a number, not 'dict'\n"}
I believe this error is documented here:
https://github.com/toastdriven/django-tastypie/issues/307
If I comment the "invitees" line and POST to EventResource the error disappears but of course the invitees are not created.
So........any one have any ideas? Is this just another error associated with issue 307 (link above) or am I doing something wrong??
Thanks very much in advance!!!!