I'm a beginner building the backend API for a social media clone using DRF. The frontend will be built later and not in Django. I'm currently using Postman to interact with the API.
I'm trying to implement a "like" feature as you would have on Facebook or Instagram. I cannot send the correct data with Postman to update the fields which bear the many-to-many relationship.
Here is some of my code:
models.py
class User(AbstractUser):
liked_haikus = models.ManyToManyField('Haiku', through='Likes')
pass
class Haiku(models.Model):
user = models.ForeignKey(User, related_name='haikus', on_delete=models.CASCADE)
body = models.CharField(max_length=255)
liked_by = models.ManyToManyField('User', through='Likes')
created_at = models.DateTimeField(auto_now_add=True)
class Likes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
haiku = models.ForeignKey(Haiku, on_delete=models.CASCADE)
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'password', 'url', 'liked_haikus']
extra_kwargs = { 'password' : {'write_only': True}}
def create(self, validated_data):
password = validated_data.pop('password')
user = User(**validated_data)
user.set_password(password)
user.save()
token = Token.objects.create(user=user)
return user
class HaikuSerializer(serializers.ModelSerializer):
class Meta:
model = Haiku
fields = ['user', 'body', 'liked_by', 'created_at']
class LikesSerializer(serializers.ModelSerializer):
model = Likes
fields = ['haiku_id', 'user_id']
views.py
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
@action(detail=True, methods=['get'])
def haikus(self, request, pk=None):
user = self.get_object()
serializer = serializers.HaikuSerializer(user.haikus.all(), many=True)
return Response(serializer.data)
class UserCreateViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.AllowAny]
class HaikuViewSet(viewsets.ModelViewSet):
queryset = Haiku.objects.all()
serializer_class = HaikuSerializer
permission_classes = [permissions.IsAuthenticated]
class LikesViewSet(viewsets.ModelViewSet):
queryset = Likes.objects.all()
serializer_class = LikesSerializer
permission_classes = [permissions.IsAuthenticated]
urls.py
router = routers.DefaultRouter(trailing_slash=False)
router.register('users', views.UserViewSet)
router.register('haikus', views.HaikuViewSet)
router.register('register', views.UserCreateViewSet)
router.register('likes', views.LikesViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('api-auth-token', obtain_auth_token, name='api_token_auth')
]
Using the Django Admin I can manually set users to like posts and the fields in the db will update and reflect in API requests.
With Postman, I've tried sending both PUT and PATCH to, for example:
http://127.0.0.1:8000/haikus/2
with "form data" where key ="liked_by" and value="3" (Where 3 is a user_id). I got a 200 response and JSON data for the endpoint back, but there was no change in the data.
I've tried GET and POST to http://127.0.0.1:8000/likes and I receive the following error message:
AttributeError: 'list' object has no attribute 'values'
I've looked at nested-serializers in the DRF docs, but they don't seem to be quite the same use-case.
How can I correct my code and use Postman to properly update the many-to-many fields?
I think I need to probably write an update function to one or several of the ViewSets or Serializers, but I don't know which one and don't quite know how to go about it.
All guidance, corrections and resources appreciated.
LikesSerializeryou forgot to passclass Metabeforemodelandfields- Florin