2013-08-29 20 views
33

Tôi có User được lưu trong hai mô hình khác nhau, UserProfileUser. Bây giờ từ quan điểm API, không ai thực sự quan tâm rằng hai điều này là khác nhau.Khung Django Rest làm cho tàu quan hệ OnetoOne cảm thấy như nó là một mô hình

Vì vậy, ở đây tôi có:

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = User 
     fields = ('url', 'username', 'first_name', 'last_name', 'email') 

class UserPSerializer(serializers.HyperlinkedModelSerializer): 
    full_name = Field(source='full_name') 
    class Meta: 
     model = UserProfile 
     fields = ('url', 'mobile', 'user','favourite_locations') 

Vì vậy, trong lĩnh vực UserPSerializeruser chỉ là một liên kết đến tài nguyên đó. Nhưng hình thành một góc nhìn của người dùng thực sự không có lý do gì để anh ấy biết về tất cả các số điện thoại User.

Có một số thủ thuật mà tôi chỉ có thể kết hợp chúng lại với nhau và trình bày chúng cho người dùng dưới dạng một mô hình hoặc tôi phải làm điều này bằng tay bằng cách nào đó.

+0

Kiểm tra [câu trả lời cho câu hỏi liên quan này] [1]. Tôi nghĩ nó bao gồm những gì bạn cần. [1]: http: // stackoverflow.com/questions/18012665 ​​/ how-can-one-customize-django-rest-framework-serializers-output/ –

+2

Câu trả lời này cũng hữu ích: http://stackoverflow.com/a/19806796/2789332 – Avril

+0

Hãy nhớ chấp nhận nếu bạn như một câu trả lời dưới đây! – bbengfort

Trả lời

12

Tôi vừa mới bắt gặp điều này; Tôi vẫn chưa tìm được giải pháp tốt đặc biệt để viết lại cho các mẫu UserUserProfile của tôi. Tôi hiện đang làm phẳng serializers tôi bằng tay bằng cách sử dụng SerializerMethodField, đó là vô cùng khó chịu, nhưng nó hoạt động:

class UserSerializer(serializers.HyperlinkedModelSerializer): 

    mobile = serializers.SerializerMethodField('get_mobile') 
    favourite_locations = serializers.SerializerMethodField('get_favourite_locations') 

    class Meta: 
     model = User 
     fields = ('url', 'username', 'first_name', 'last_name', 'email', 'mobile', 'favourite_locations') 

    def get_mobile(self, obj): 
     return obj.get_profile().mobile 

    def get_favourite_locations(self, obj): 
     return obj.get_profile().favourite_locations 

Đây là khủng khiếp dẫn sử dụng, nhưng bạn kết thúc với:

{ 
    "url": "http://example.com/api/users/1", 
    "username": "jondoe", 
    "first_name": "Jon", 
    "last_name": "Doe", 
    "email": "[email protected]", 
    "mobile": "701-680-3095", 
    "favourite_locations": [ 
     "Paris", 
     "London", 
     "Tokyo" 
    ] 
} 

nào, tôi đoán là những gì bạn đang tìm kiếm.

+2

Tôi nghĩ rằng một SerializerMethodField là chỉ đọc, do đó, điều này sẽ không cho phép tạo hoặc sửa đổi các trường hồ sơ thông qua tài nguyên người dùng. Bạn cũng có thể nhận được chỉ đọc bằng cách gõ * ít * ít hơn bằng cách sử dụng gợi ý trong câu trả lời của @ kahlo. (Ví dụ: 'mobile = serializers.CharField (source = 'profile.mobile', read_only = True)'). – medmunds

+0

'mobile = serializers.SerializerMethodField()' sẽ sử dụng hàm 'get_mobile' theo mặc định và sẽ ném một lỗi cho dự phòng nếu bạn chỉ định trường theo cách thủ công. – andyn

6

tôi sẽ thực hiện những sửa đổi trên UserPSerializer như các lĩnh vực sẽ không phát triển:

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    class Meta: 
     model = User 
     fields = ('url', 'username', 'first_name', 'last_name', 'email') 

class UserPSerializer(serializers.HyperlinkedModelSerializer): 
    url = serializers.CharField(source='user.url') 
    username = serializers.CharField(source='user.username') 
    first_name = serializers.CharField(source='user.first_name') 
    last_name = serializers.CharField(source='user.last_name') 
    email = serializers.CharField(source='user.email') 

    class Meta: 
     model = UserProfile 
     fields = ('mobile', 'favourite_locations', 
        'url', 'username', 'first_name', 'last_name', 'email') 
+4

đây là một giải pháp sạch để NHẬN người dùng, nhưng không hoạt động đối với BÀI ĐĂNG người dùng mới. – Xuan

+1

Chỉ cần ghi đè cập nhật và tạo .. –

29

Bạn có thể đăng và PUT với @kahlo's approach nếu bạn cũng ghi đè lên tạo và phương pháp cập nhật trên serializer của bạn.

Cho một mô hình hồ sơ như thế này:

class Profile(models.Model): 
    user = models.OneToOneField(User) 
    avatar_url = models.URLField(default='', blank=True) # e.g. 

Dưới đây là một serializer người dùng mà cả đọc và viết các trường bổ sung hồ sơ (s):

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    # A field from the user's profile: 
    avatar_url = serializers.URLField(source='profile.avatar_url', allow_blank=True) 

    class Meta: 
     model = User 
     fields = ('url', 'username', 'avatar_url') 

    def create(self, validated_data): 
     profile_data = validated_data.pop('profile', None) 
     user = super(UserSerializer, self).create(validated_data) 
     self.update_or_create_profile(user, profile_data) 
     return user 

    def update(self, instance, validated_data): 
     profile_data = validated_data.pop('profile', None) 
     self.update_or_create_profile(instance, profile_data) 
     return super(UserSerializer, self).update(instance, validated_data) 

    def update_or_create_profile(self, user, profile_data): 
     # This always creates a Profile if the User is missing one; 
     # change the logic here if that's not right for your app 
     Profile.objects.update_or_create(user=user, defaults=profile_data) 

API kết quả trình bày một tài nguyên dùng phẳng , như mong muốn:

GET /users/5/ 
{ 
    "url": "http://localhost:9090/users/5/", 
    "username": "test", 
    "avatar_url": "http://example.com/avatar.jpg" 
} 

và bạn có thể bao gồm tiểu sử củaTrườngtrong cả hai yêu cầu POST và PUT. (Và DELETE trên tài nguyên người dùng cũng sẽ xóa mô hình Hồ sơ của nó, mặc dù đó chỉ là thác xóa bình thường của Django.)

Logic ở đây sẽ tạo mô hình Hồ sơ cho Người dùng nếu thiếu (trên bất kỳ cập nhật nào). Với người dùng và hồ sơ, đó có thể là những gì bạn muốn. Đối với các mối quan hệ khác nó có thể không, và bạn sẽ cần phải thay đổi logic cập nhật hoặc tạo. (Đó là lý do tại sao DRF doesn't automatically write through a nested relationship cho bạn.)

Các vấn đề liên quan