0

非常に単純なネストされたモデルがあります。

class Game(models.Model):
  name = models.CharField(max_length=200)
  description = models.TextField()
  user = models.ForeignKey(User)

class Activity(models.Model):
  game = models.ForeignKey(Game, related_name = 'activities')
  type = models.CharField(max_length=4)
  score = models.DecimalField(max_digits=3, decimal_places=2)

管理者経由でオブジェクトを作成でき、スムーズに動作します。次に、TastyPie を使用して API を作成しました。私のリソースは次のようになります。

class GameResource(ModelResource):
  user = fields.ToOneField(UserResource, 'user')
  app = fields.ToOneField(AppResource, 'app')
  activities = fields.ToManyField('api.resources.ActivityResource', 'activities', full=True, related_name='activity')

  class Meta:
    queryset = Game.objects.all()
    resource_name = 'games'
    list_allowed_methods = ['get','post']
    detail_allowed_methods = ['get','put','post','delete']
    authentication = ApiKeyTokenAuthentication()
    authorization = Authorization()
    serializer = CustomJSONSerializer(formats=['json'])

  def apply_authorization_limits(self, request, object_list):
    return object_list.filter(user=request.user)

  def obj_create(self, bundle, request=None, **kwargs):
    requestApp = App.objects.get(api_key=request.api_key)
    return super(GameResource, self).obj_create(bundle, request, app=requestApp)

  def get_object_list(self, request):
    return super(GameResource, self).get_object_list(request).filter(app__api_key=request.api_key)


class ActivityResource(ModelResource): 
  game = fields.ForeignKey(GameResource, 'game')

  class Meta:
    queryset = Activity.objects.all()
    resource_name = 'activities'
    list_allowed_methods = ['get','post']
    detail_allowed_methods = ['get','put','post','delete']
    authentication = ApiKeyTokenAuthentication()
    authorization = Authorization()
    serializer = CustomJSONSerializer(formats=['json'])

  def apply_authorization_limits(self, request, object_list):
    return object_list.filter(game__user=request.user)

  def obj_create(self, bundle, request=None, **kwargs):
        return super(ActivityResource, self).obj_create(bundle, request)

  def get_object_list(self, request):
        return super(ActivityResource, self).get_object_list(request).filter(game__app__api_key=request.api_key)

ゲームにネストされたアクティビティを使用して、この辞書をアプリから投稿します。

{
    name = "Monte";
    description = "To search for the holy grail.";
    user = "/api/v1/users/2/";
    activities =     (
                {
            type = "eggs";
            score = "0.50";
        }
    );
}

その結果、Game はデータベースに作成されますが、TastyPie がネストされた Activity オブジェクトを作成しようとすると、エラーが発生します。このエラーは、アクティビティのリストを取得しようとすると、api_key と一致するものが見つからないことを示しています。オブジェクトを取得しようとしている理由がわかりません。また、リクエストを送信したアプリでゲームを正しく作成している場合、NoneType がどこから来たのかわかりません。request.api_key に一致するアプリを見つけて、それをゲームのアプリとして設定していることがわかります。

"error_message": "'NoneType' object has no attribute 'api_key'"
    super(ActivityResource, self).get_object_list(request).filter(game__app__api_key=request.api_key)\n\nAttributeError: 'NoneType' object has no attribute 'api_key'\n"

私は何が欠けていますか?リソースとアクティビティを取得する方法に何か問題がありますか?

補足として...辞書を投稿できます:

    {
        game = "/api/v1/games/2/"
        type = "eggs";
        score = "0.50";
    }

それをアクティビティに投稿すると、アクティビティが正しく作成されます。そして、API を介してアクティビティを取得すると、そのように見えます。

したがって、問題はアクティビティを作成することではなく、ゲームにネストされたアクティビティを作成することだけです。

アップデート:

いくつかのブレークポイントを設定したところ、resource_from_data で obj_update が呼び出され、リクエストが送信されていないため、request = NoneType であることがわかりました。これは TastyPie のバグですか?

def resource_from_data(self, fk_resource, data, request=None, related_obj=None, related_name=None):
    """
    Given a dictionary-like structure is provided, a fresh related
    resource is created using that data.
    """
    # Try to hydrate the data provided.
    data = dict_strip_unicode_keys(data)
    fk_bundle = fk_resource.build_bundle(data=data, request=request)

    if related_obj:
        fk_bundle.related_obj = related_obj
        fk_bundle.related_name = related_name

    # We need to check to see if updates are allowed on the FK
    # resource. If not, we'll just return a populated bundle instead
    # of mistakenly updating something that should be read-only.
    if not fk_resource.can_update():
        return fk_resource.full_hydrate(fk_bundle)

    try:
        return fk_resource.obj_update(fk_bundle, request, **data)
    except NotFound:
        try:
            # Attempt lookup by primary key
            lookup_kwargs = dict((k, v) for k, v in data.iteritems() if getattr(fk_resource, k).unique)

            if not lookup_kwargs:
                raise NotFound()

            return fk_resource.obj_update(fk_bundle, **lookup_kwargs)
        except NotFound:
            return fk_resource.full_hydrate(fk_bundle)
    except MultipleObjectsReturned:
        return fk_resource.full_hydrate(fk_bundle)
4

0 に答える 0