1

当我创建具有外部关系的新资源时,指定为,即,{"pk": 20}我创建了一个新的不需要的 FK 项。

我有Order与模型有关系的模型类Language,因此在创建 Order 实例时,我可能必须指定订单的语言。语言列表应该是恒定的,用户不能修改现有语言或创建新语言。

Order资源:

class OrderResource(ModelResource):
    user = fields.ForeignKey(UserResource, 'user', null=True, full=True)
    src_lang = fields.ForeignKey(LanguageResource, 'src_lang', null=True, full=True)
    dst_lang = fields.ForeignKey(LanguageResource, 'dst_lang', null=True, full=True)

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

    class Meta:
        resource_name = 'orders'
        queryset = Order.objects.all()
        serializer = Serializer(['json'])

        authentication = MultiAuthentication(SessionAuthentication(), ApiKeyAuthentication())
        authorization = ResourceAuthorization() 

这是一个Language资源:

class Language(models.Model):
    name = models.CharField(max_length=100)
    code = models.CharField(max_length=100)


class LanguageResource(ModelResource):
    class Meta:
        resource_name = 'languages'
        queryset = Language.objects.all()
        allowed_methods = ['get']
        authorization = ReadOnlyAuthorization()
        serializer = Serializer(['json'])

我正在尝试Order使用 jQuery 创建一个新的:

var data = JSON.stringify({
    "comment": "Something random",
    "src_lang": {"pk": "20"},
    "dst_lang": "/api/v2/languages/72/"
});

$.ajax({
    type: 'POST',
    url: '/api/v2/orders/',
    data: data,
    dataType: "json",
    contentType: "application/json"
});

它没有设置pk:20tosrc_lang_id字段,而是创建一个Language带有空字段的新 forsrc_lang并为 设置正确的值dst_lang。但是空字段受Language模型定义的限制。它是如何保存的?

这也很奇怪,因为我直接指定了语言模型的只读访问权限,以及get访问受支持语言列表的唯一方法。

如果我将类的语言字段声明OrderResource为 ie: src_lang = fields.ForeignKey(LanguageResource, 'src_lang', null=True, full=True, readonly=True),它不会创建任何内容,但也不会为外键设置任何值。

所以,我只需要指定一种现有的语言,我不需要创建它。

更新

ResourceAuthorization

class ResourceAuthorization(Authorization):
    def is_authorized(self, request, object=None):
        user = getattr(request, 'user', None)
        if not user:
            return False

        return user.is_authenticated()

    def apply_limits(self, request, object_list):
        if request and hasattr(request, 'user'):
            if request.user.is_superuser:
                return object_list

            return object_list.filter(user=request.user)

        return object_list.none()

更新 2

我发现没有什么比让字段只读和覆盖obj_create方法更聪明的了:

class OrderResource(ModelResource):
    user = fields.ForeignKey(UserResource, 'user', null=True, full=True)
    src_lang = fields.ForeignKey(LanguageResource, 'src_lang', null=True, full=True, blank=True, readonly=True)
    dst_lang = fields.ForeignKey(LanguageResource, 'dst_lang', null=True, full=True, blank=True, readonly=True)

    def obj_create(self, bundle, request=None, **kwargs):
        src_lang_id, dst_lang_id = bundle.data.get('src_lang', None), bundle.data.get('dst_lang', None)

        if not all([src_lang_id, dst_lang_id]):
            raise BadRequest('You should specify both source and destination language codes')

        src_lang, dst_lang = Language.objects.guess(src_lang_id), Language.objects.guess(dst_lang_id)
        if not all([src_lang, dst_lang]):
            raise BadRequest('You should specify both source and destination language codes')

        return super(OrderResource, self).obj_create(
            bundle, request, user=request.user, src_lang=src_lang, dst_lang=dst_lang
        )

    class Meta:
        resource_name = 'orders'
        queryset = Order.objects.all()
        serializer = Serializer(['json'])

        authentication = MultiAuthentication(SessionAuthentication(), ApiKeyAuthentication())
        authorization = ResourceAuthorization()
4

2 回答 2

2

如您的问题的答案中所述应对src_lang应于资源,而不是其他值。我怀疑当 POST 发生并且它没有找到资源pk=20时,它会创建一个新Language对象并在没有 Django 模型验证的情况下调用save,从而允许在 created 中存在一个空白字段Language

强制只读类型资源的一种方法是创建一个不允许obj_create.

class ReadOnlyLanguageResource(ModelResource):
    # All the meta stuff here.
    def obj_create(self):
        # This should probably raise some kind of http error exception relating
        # to permission denied rather than Exception.
        raise Exception("Permission denied, cannot create new language resource")

然后从您的资源中引用此资源Order,仅覆盖src_lang指向您的只读资源的字段。

class OrderResource(ModelResource):
    user = fields.ForeignKey(UserResource, 'user', null=True, full=True)
    src_lang = fields.ForeignKey(ReadOnlyLanguageResource, 'src_lang')
    dst_lang = fields.ForeignKey(ReadOnlyLanguageResource, 'dst_lang')

任何引用现有资源的请求都将正常完成(但您需要正确引用资源,而不是使用pk=20)。任何引用未知语言的请求都将失败,因为Language无法创建新对象。

于 2013-01-20T23:54:40.803 回答
1

您应该以对应的src_lang格式指定./api/v2/languages/72/pk=20

其次究竟是ResourceAuthorization什么?可能对您有用的文档列表。ReadOnlyAuthorization

授权也应用资源,而不是底层模型。在为 创建新对象时fk,它不使用 REST Api 而是使用django.db.models它的权限。因此,授权可能不适用于外键约束。

于 2013-01-20T19:55:21.017 回答