更新给定资源tastypie中的两个模型

时间:2013-05-09 04:14:22

标签: django tastypie

问题陈述很简单, 2型号:UserGames,UserHost

用户发出帖子请求以加入游戏,然后在UserGames中创建记录,如果在请求中传递了Hosting参数,则创建UserGames和UserHost记录。 UserHost具有对UserGames的外键引用。

我可以在**

中创建UserGames记录
  • obj_create

**但我需要记录UserGames对象ID才能在UserHost中创建记录。

第二个问题,我需要在输出中返回一个数组UserGames if user is not hosting)或else UserGames + UserHost combined array

1 个答案:

答案 0 :(得分:4)

我尝试使用abstract model实现此功能,然后通过ModelResource公开。我必须覆盖obj_createget_resource_uri方法。

请查看示例代码(我已在本地计算机上测试过这个代码)。

模型

from django.db import models
from django.contrib.auth.models import User


class UserGame(models.Model):
    user = models.ForeignKey(User)
    # more fields like name etc.
    name = models.CharField("name", max_length=40)

    def __unicode__(self):
        return self.name


class UserHost(models.Model):
    game = models.ForeignKey(UserGame)
    # more fields like hostname etc.
    hostname = models.CharField("host name", max_length=40)

    def __unicode__(self):
        return self.hostname


class JoinGame(models.Model):
    game = models.ForeignKey(UserGame)
    host = models.ForeignKey(UserHost)

    class Meta:
        abstract = True

使用Tastypie

的API资源
from django.contrib.auth.models import User

from tastypie import fields
from tastypie.authentication import (BasicAuthentication, ApiKeyAuthentication,
                                     MultiAuthentication)
from tastypie.authorization import Authorization
from tastypie.resources import Resource, ModelResource
from tastypie.exceptions import BadRequest

from .models import UserGame, UserHost, JoinGame


class UserResource(ModelResource):
    class Meta:
        resource_name = "user"
        # For authentication, allow both basic and api key so that the key
        # can be grabbed, if needed.
        authentication = MultiAuthentication(BasicAuthentication(),
                                             ApiKeyAuthentication())
        authorization = Authorization()

        # Because this can be updated nested under the other Resources.
        # It needs put/patch to be able to handle partial updates.
        allowed_methods = ['get', 'patch', 'put', ]
        always_return_data = True
        queryset = User.objects.all().select_related("api_key")
        excludes = ['is_active', 'is_staff', 'is_superuser', 'date_joined',
                    'last_login', 'password']


class UserGameResource(ModelResource):
    user = fields.ForeignKey(UserResource, 'user', full=True)

    class Meta:
        resource_name = "user_game"
        authentication = ApiKeyAuthentication()
        authorization = Authorization()

        # Because this can be updated nested under the other Resources.
        # It needs put/patch to be able to handle partial updates.
        allowed_methods = ['get', 'post', 'patch', 'put']
        always_return_data = True
        queryset = UserGame.objects.all()


class UserHostResource(ModelResource):
    resource_name = "user_host"
    user_game = fields.ForeignKey(UserGameResource, 'game', full=True)

    class Meta:
        authentication = ApiKeyAuthentication()
        authorization = Authorization()

        # Because this can be updated nested under the other Resources.
        # It needs put/patch to be able to handle partial updates.
        allowed_methods = ['get', 'post', 'patch', 'put']
        always_return_data = True
        queryset = UserHost.objects.all()

JoinGameResource

class JoinGameResource(Resource):
    game = fields.ForeignKey(UserGameResource, "game", null=True, full=True)
    host = fields.ForeignKey(UserHostResource, "host", null=True, full=True)

    class Meta:
        resource_name = "join_game"
        object_class = JoinGame
        authentication = ApiKeyAuthentication()
        authorization = Authorization()

        # Because this can be updated nested under the other Resources.
        # It needs put/patch to be able to handle partial updates.
        list_allowed_methods = ['post']
        detail_allowed_methods = []
        fields = ["game", "host"]
        always_return_data = True

    def hydrate(self, bundle):
        if "game" not in bundle.data:
            raise BadRequest("Must provide 'game' when joining a game.")
        return bundle

    def obj_create(self, bundle, **kwargs):
        try:
            game = bundle.data.get("game")
            game_bundle = self.build_bundle(obj=UserGame(), data=game,
                                            request=bundle.request)
            updated_game_bundle = UserGameResource().obj_create(
                game_bundle, **kwargs)
            bundle.obj.game = updated_game_bundle.obj
        except KeyError:
            raise BadRequest("Must provide 'game' when joining a game.")

        try:
            host = bundle.data.get("host")
            host_bundle = self.build_bundle(obj=UserHost(), data=host,
                                            request=bundle.request)
            updated_host_bundle = UserHostResource().obj_create(
                host_bundle, game=updated_game_bundle.obj, **kwargs)
            bundle.obj.host = updated_host_bundle.obj
        except KeyError:
            pass
            #raise BadRequest("Must provide 'host' when joining a host.")

        return bundle

    def get_resource_uri(self, updated_bundle):
        # Since JoinGame is abstract model, pk won't be available
        # So, get_resource_uri method of ModelResource will raise exception
        # Let's override that
        return None

URLS

from .api import (
    UserResource, UserGameResource, UserHostResource, JoinGameResource)
from django.conf.urls import patterns, include
from tastypie.api import Api

# Create an empty pattern so that we can just build it using +=
urlpatterns = patterns(None)

#==============================================================================
# API Resources
#==============================================================================
v1_api = Api(api_name='v1')
v1_api.register(UserResource())
v1_api.register(UserGameResource())
v1_api.register(UserHostResource())
v1_api.register(JoinGameResource())

urlpatterns += patterns(
    '',
    (r'^api/', include(v1_api.urls)),
)

样品申请正文

{
    "game": {
        "name": "New Game",
        "user": "/api/v1/user/1/"
    },
    "host": {
        "hostname": "New Host name"
    }
}

样本回复正文

{
    "game": {
        "id": 15,
        "name": "New Game",
        "resource_uri": "/api/v1/user_game/15/",
        "user": {
            "email": "psjinx@example.com",
            "first_name": "",
            "id": 1,
            "last_name": "",
            "resource_uri": "/api/v1/user/1/",
            "username": "psjinx"
        }
    },
    "host": {
        "hostname": "New Host name",
        "id": 13,
        "resource_uri": "/api/v1/userhost/13/",
        "user_game": {
            "id": 15,
            "name": "New Game",
            "resource_uri": "/api/v1/user_game/15/",
            "user": {
                "email": "psjinx@example.com",
                "first_name": "",
                "id": 1,
                "last_name": "",
                "resource_uri": "/api/v1/user/1/",
                "username": "psjinx"
            }
        }
    },
    "resource_uri": null
}