Matt Stern
Matt Stern

Reputation: 727

tastypie PUT works but POST doesn't

I'm trying to implement a simple Django service with a RESTful API using tastypie. My problem is that when I try to create a WineResource with PUT, it works fine, but when I use POST, it returns a HTTP 501 error. Reading the tastypie documentation, it seems like it should just work, but it's not.

Here's my api.py code:

    class CustomResource(ModelResource):
    """Provides customizations of ModelResource"""
    def determine_format(self, request):
    """Provide logic to provide JSON responses as default"""
    if 'format' in request.GET:
        if request.GET['format'] in FORMATS:
        return FORMATS[request.GET['format']]
        else:
        return 'text/html' #Hacky way to prevent incorrect formats
    else:
        return 'application/json'

class WineValidation(Validation):
    def is_valid(self, bundle, request=None):
    if not bundle.data:
        return {'__all__': 'No data was detected'}

    missing_fields = []
    invalid_fields = []

    for field in REQUIRED_WINE_FIELDS:
        if not field in bundle.data.keys():
        missing_fields.append(field)
    for key in bundle.data.keys():
        if not key in ALLOWABLE_WINE_FIELDS:
        invalid_fields.append(key)

    errors = missing_fields + invalid_fields if request.method != 'PATCH' \
        else invalid_fields

    if errors:
        return 'Missing fields: %s; Invalid fields: %s' % \
            (', '.join(missing_fields), ', '.join(invalid_fields))
    else:
        return errors

class WineProducerResource(CustomResource):
    wine = fields.ToManyField('wines.api.WineResource', 'wine_set', 
                 related_name='wine_producer')
    class Meta:
    queryset = WineProducer.objects.all()
    resource_name = 'wine_producer'
    authentication = Authentication() #allows all access
    authorization = Authorization() #allows all access

class WineResource(CustomResource):
    wine_producer = fields.ForeignKey(WineProducerResource, 'wine_producer')

    class Meta:
    queryset = Wine.objects.all()
    resource_name = 'wine'
    authentication = Authentication() #allows all access
    authorization = Authorization() #allows all access
    validation = WineValidation()
    filtering = {
        'percent_new_oak': ('exact', 'lt', 'gt', 'lte', 'gte'),
        'percentage_alcohol': ('exact', 'lt', 'gt', 'lte', 'gte'),
        'color': ('exact', 'startswith'),
        'style': ('exact', 'startswith')

    }

    def hydrate_wine_producer(self, bundle):
    """Use the provided WineProducer ID to properly link a PUT, POST,
    or PATCH to the correct WineProducer instance in the db"""
    #Workaround since tastypie has bug and calls hydrate more than once
    try:
        int(bundle.data['wine_producer'])
    except ValueError:
        return bundle
    bundle.data['wine_producer'] = '/api/v1/wine_producer/%s/' % \
                        bundle.data['wine_producer']
    return bundle

Any help is greatly appreciated! :-)

Upvotes: 2

Views: 2655

Answers (1)

josh.bohde
josh.bohde

Reputation: 416

This usually means that you are sending the POST to a detail uri, e.g. /api/v1/wine/1/. Since POST means treat the enclosed entity as a subordinate, sending the POST to the list uri, e.g. /api/v1/wine/, is probably what you want.

Upvotes: 7

Related Questions