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'])

私はOrderjQueryで新しいものを作成しようとしています:

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:20toフィールドを設定する代わりに、の空のフィールドでsrc_lang_id新しいを作成し、の正しい値を設定します。ただし、空のフィールドはモデル定義で制限されます。どのようにそれを保存しますか?Languagesrc_langdst_langLanguage

getまた、言語モデルの読み取り専用アクセスと、サポートされている言語リストにアクセスするための唯一の方法を直接指定したので、それは十分に奇妙です。

OrderResourceクラスの言語フィールドを次のように宣言すると、つまり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が発生し、リソースが見つからない場合、新しいオブジェクトが作成され、Djangoモデルの検証なしで呼び出され、作成されたに空白のフィールドが存在する可能性があります。pk=20LanguagesaveLanguage

読み取り専用タイプのリソースを強制する1つの方法は、を許可しないリソースを作成すること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 に答える