J'ai mon User
enregistré dans deux modèles différents, UserProfile
et User
. Du point de vue API, personne ne se soucie vraiment que ces deux-là soient différents.
Alors là, j'ai:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'first_name', 'last_name', 'email')
et
class UserPSerializer(serializers.HyperlinkedModelSerializer):
full_name = Field(source='full_name')
class Meta:
model = UserProfile
fields = ('url', 'mobile', 'user','favourite_locations')
Ainsi, dans UserPSerializer
, le champ user
n'est qu'un lien vers cette ressource. Mais du point de vue de l'utilisateur, il n'a vraiment aucune raison de connaître User
.
Existe-t-il des astuces avec lesquelles je peux simplement les mélanger et les présenter à l'utilisateur comme un modèle ou dois-je le faire manuellement d'une manière ou d'une autre.
Vous pouvez POST et PUT avec approche @ kahlo si vous remplacez également les méthodes de création et de mise à jour sur votre sérialiseur.
Étant donné un modèle de profil comme celui-ci:
class Profile(models.Model):
user = models.OneToOneField(User)
avatar_url = models.URLField(default='', blank=True) # e.g.
Voici un sérialiseur utilisateur qui lit et écrit les champs de profil supplémentaires:
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)
L'API résultante présente une ressource utilisateur plate, comme souhaité:
GET /users/5/
{
"url": "http://localhost:9090/users/5/",
"username": "test",
"avatar_url": "http://example.com/avatar.jpg"
}
et vous pouvez inclure le profil du avatar_url
champ dans les deux POST et PUT. (Et DELETE sur la ressource utilisateur supprimera également son modèle de profil, bien que ce ne soit que la cascade de suppression normale de Django.)
La logique ici va toujours créer un modèle de profil pour l'utilisateur s'il est manquant (sur toute mise à jour). Avec les utilisateurs et les profils, c'est probablement ce que vous voulez. Pour d'autres relations, il se peut que ce ne soit pas le cas et vous devrez modifier la logique de mise à jour ou de création. (C'est pourquoi DRF n'écrit pas automatiquement via une relation imbriquée pour vous.)
Je viens de rencontrer ça; Je n'ai pas encore trouvé de bonne solution, en particulier pour réécrire sur mes modèles User
et UserProfile
. J'aplatis actuellement mes sérialiseurs manuellement en utilisant le SerializerMethodField
, ce qui est extrêmement irritant, mais cela fonctionne:
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
C'est horriblement manuel, mais vous vous retrouvez avec:
{
"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"
]
}
Je suppose que c'est ce que vous cherchez.
Je voudrais implémenter les modifications sur le UserPSerializer
car les champs ne vont pas augmenter:
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')