2015-03-31 17 views
7

Tôi có URL sau trong urlpatterns tôi:django-nghỉ ngơi-framework HyperlinkedIdentityField với nhiều args tra cứu

url(r'^user/(?P<user_pk>[0-9]+)/device/(?P<uid>[0-9a-fA-F\-]+)$', views.UserDeviceDetailView.as_view(), name='user-device-detail'), 

thông báo nó có hai lĩnh vực: user_pk, và uid. URL sẽ trông giống như sau: https://example.com/user/410/device/c7bda191-f485-4531-a2a7-37e18c2a252c.

Trong chế độ xem chi tiết cho mô hình này, tôi đang cố gắng điền vào trường url sẽ chứa liên kết quay lại mô hình.

Trong serializer, tôi có:

url = serializers.HyperlinkedIdentityField(view_name="user-device-detail", lookup_field='uid', read_only=True) 
tuy nhiên

, nó không Tôi nghĩ rằng vì URL có hai lĩnh vực:

django.core.exceptions.ImproperlyConfigured: không thể phân giải URL cho mối quan hệ siêu liên kết bằng cách sử dụng tên chế độ xem "user-device-detail". Bạn có thể không bao gồm mô hình liên quan trong API của mình hoặc đã định cấu hình sai thuộc tính lookup_field trên trường này.

Bạn sử dụng số HyperlinkedIdentityField (hoặc bất kỳ số nào trong số Hyperlink*Field) khi URL có hai hoặc nhiều mục mẫu URL? (trường tra cứu)?

Trả lời

5

Tôi không chắc liệu bạn đã giải quyết được vấn đề này chưa, nhưng điều này có thể hữu ích cho bất kỳ ai khác có vấn đề này. Không có nhiều bạn có thể làm ngoài việc ghi đè HyperlinkedIdentityField và tạo ra một trường serializer tùy chỉnh cho mình. Một ví dụ về vấn đề này nằm ở cùng liên kết github dưới đây (cùng với một số mã nguồn để có được xung quanh nó):

https://github.com/tomchristie/django-rest-framework/issues/1024

Mã được chỉ định có này:

from rest_framework.relations import HyperlinkedIdentityField 
from rest_framework.reverse import reverse 

class ParameterisedHyperlinkedIdentityField(HyperlinkedIdentityField): 
    """ 
    Represents the instance, or a property on the instance, using hyperlinking. 

    lookup_fields is a tuple of tuples of the form: 
     ('model_field', 'url_parameter') 
    """ 
    lookup_fields = (('pk', 'pk'),) 

    def __init__(self, *args, **kwargs): 
     self.lookup_fields = kwargs.pop('lookup_fields', self.lookup_fields) 
     super(ParameterisedHyperlinkedIdentityField, self).__init__(*args, **kwargs) 

    def get_url(self, obj, view_name, request, format): 
     """ 
     Given an object, return the URL that hyperlinks to the object. 

     May raise a `NoReverseMatch` if the `view_name` and `lookup_field` 
     attributes are not configured to correctly match the URL conf. 
     """ 
     kwargs = {} 
     for model_field, url_param in self.lookup_fields: 
      attr = obj 
      for field in model_field.split('.'): 
       attr = getattr(attr,field) 
      kwargs[url_param] = attr 

     return reverse(view_name, kwargs=kwargs, request=request, format=format) 

này nên nơi làm việc, trong trường hợp của bạn, bạn sẽ gọi nó là như thế này:

url = ParameterisedHyperlinkedIdentityField(view_name="user-device-detail", lookup_fields=(('<model_field_1>', 'user_pk'), ('<model_field_2>', 'uid')), read_only=True) 

đâu <model_field_1><model_field_2> là những lĩnh vực người mẫu, có lẽ 'id' và 'uid' trong trường hợp của bạn.

Lưu ý rằng vấn đề trên đã được báo cáo cách đây 2 năm, tôi không biết họ đã bao gồm thứ gì đó như thế trong các phiên bản DRF mới hơn (tôi chưa tìm thấy) nhưng mã trên hoạt động cho tôi.

+0

Cảm ơn. Tôi đã kết thúc tạo lớp con của riêng HyperlinkedIdentityField giống như phương thức "to_representation()" được ghi đè: def to_representation (self, value): trả về ngược lại ('user-device-detail', kwargs = {'user_pk': value.owner_id, 'uid': value.uid}, yêu cầu = self.context ['request']) – SuperDuperTango

+0

Đánh dấu phần này là được chấp nhận mặc dù tôi chưa thử. điều này có vẻ như một cách hợp lý (và có thể mở rộng) để giải quyết vấn đề. – SuperDuperTango

+0

Giải pháp chỉ hoạt động khi bạn có thể trích xuất tất cả các khóa cần thiết từ 'obj' (trực tiếp trên gián tiếp). Thật không may trong trường hợp phụ thuộc nhiều-nhiều, nó là không thể. – prokher