44

私は2 つの異なるモデルにUser保存しています。API の観点から見ると、この 2 つが異なることを気にする人はいません。UserProfileUser

だからここに私が持っています:

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

そのためUserPSerializer、フィールドuserにはそのリソースへのリンクが表示されます。しかし、ユーザーの観点から見ると、彼が知る理由はまったくありませんUser

それらをマッシュアップして 1 つのモデルとしてユーザーに提示できるトリックはありますか、それとも何らかの方法でこれを手動で行う必要がありますか。

4

3 に答える 3

34

シリアライザーのcreate メソッドと update メソッドもオーバーライドすると、 @kahlo のアプローチで POST と PUT を実行できます。

次のようなプロファイル モデルがあるとします。

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

追加のプロファイル フィールドの読み取りと書き込みの両方を行うユーザー シリアライザーを次に示します。

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 は、必要に応じてフラットなユーザー リソースを提供します。

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

avatar_urlまた、プロファイルのフィールドを POST 要求と PUT 要求の両方に含めることができます。(そして、ユーザー リソースの DELETE は、プロファイル モデルも削除しますが、これは Django の通常の削除カスケードにすぎません。)

ここでのロジックは、ユーザーのプロファイル モデルが欠落している場合 (更新時に)常に作成します。ユーザーとプロファイルを使用すると、おそらくそれが必要になります。他の関係についてはそうではない可能性があり、更新または作成ロジックを変更する必要があります。(これが、DRFがネストされたリレーションシップを介して自動的に書き込まない理由です。)

于 2015-02-26T03:08:05.017 に答える
12

私はこれに出くわしました。特に私のモデルUserUserProfileモデルに書き戻すための良い解決策をまだ見つけていません。私は現在、シリアライザーを手動で使用してフラット化していますがSerializerMethodField、これは非常にイライラしますが、動作します:

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

これは恐ろしく手動ですが、最終的には次のようになります。

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

これは、あなたが探しているものだと思います。

于 2014-01-15T02:17:33.823 に答える
6

UserPSerializerフィールドが成長しないため、に変更を実装します。

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')
于 2014-05-03T12:30:31.337 に答える