0

问题陈述很简单,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.

4

1 回答 1

4

我尝试使用抽象模型来实现它,然后通过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()

加入游戏资源

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

网址

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
}
于 2013-05-09T08:13:31.207 回答