2013-01-20 110 views
1

當我創建與外國關係的新資源,指定爲,即{"pk": 20},我得到創建了一個新的不必要的FK-項目。tastypie - 禁用嵌套的對象創建

我有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:20src_lang_id d,它會創建一個新的Languagesrc_lang空字段,併爲dst_lang正確的值。但空的字段受限於Language模型定義。它如何保存它?

還因爲我已經直線指定語言模型只讀訪問,只get用於訪問支持的語言列表方法是自嘆不如。

如果我將OrderResource類的語言字段聲明爲src_lang = fields.ForeignKey(LanguageResource, 'src_lang', null=True, full=True, readonly=True),它不會創建任何內容,但也不會爲外鍵設置任何值。

所以,我只需要指定一個existant語言,我不需要創建它。

UPDATE

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() 

回答

2

正如this回答你的問題,src_lang應該對應於資源,而不是一些其他的價值。我懷疑當POST發生並且沒有找到資源pk=20時,它會創建一個新的Language對象,並且在沒有Django模型驗證的情況下調用save,從而允許在創建的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

1

您應該指定src_lang在格式/api/v2/languages/72/對應pk=20

其次究竟是什麼ResourceAuthorizationdocumentation列出了ReadOnlyAuthorization這可能對您有用。

而且授權應用的資源,而不是底層模型。當爲fk創建新對象時,它不使用REST Api,但使用django.db.models及其權限。所以授權可能不適用於通過外鍵約束。

+0

我看到它應該指定的格式,我不明白爲什麼它會創建一個新的'Language'實例。如果我將使用'/ api/v2/languages/20 /'作爲src_lang,它就可以正常工作。 'ResourceAuthorization'是[每用戶授權](http://django-tastypie.readthedocs.org/en/latest/cookbook.html#creating-per-user-resources) –

+0

我現在看到ResourceAuthorization,但我是不確定其正確性。 –