Инкрементирование целочисленного поля в Django
Я создаю простое приложение для ведения блога и хотел бы, чтобы пользователи могли поставить лайк записи.
С точки зрения масштабируемости я решил, что будет лучше иметь лайки в виде отдельной таблицы, состоящей из указателей на пользователя и пост.
Мне удалось включить запрос поста, добавив like в модель, однако поле likes
в модели поста не увеличивается.
Я пробовал использовать простую технику likes += 1
в сериализаторе, но это не привело к изменениям, и теперь я использую строку F
, но все равно никаких изменений не происходит. Я все еще довольно новичок в Django и подозреваю, что это может быть связано с тем, что я пытаюсь обновить поле в другой модели в сериализаторе CreateAPIView
, но я не уверен.
Вот что у меня есть на данный момент
# views.py
class LikeView(generics.CreateAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
queryset = Like.objects.all()
serializer_class = LikeSerializer
def like(self, request, format=None):
serializer = self.serializer_class(data=request.data)
if(serializer.is_valid()):
user_id = serializer.data.get('user_id')
post_id = serializer.data.get('post_id')
l = Like(user_id=user_id, post_id=post_id)
l.save()
# likes field not updating with this
post = Post.objects.get(id=post_id)
post.likes = F('likes') + 1
post.save()
return Response(LikeSerializer(l).data, status=status.HTTP_200_OK)
return Response(serializer.errors(), status=status.HTTP_400_BAD_REQUEST)
#models.py
class Post(models.Model):
id = models.CharField(max_length=36, default=generate_unique_id, primary_key=True)
title = models.CharField(max_length=50)
content = models.TextField()
likes = models.IntegerField(default=0, blank=True)
pub_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
class Like(models.Model):
user_id = models.ForeignKey(User, related_name='user_id', on_delete=models.CASCADE)
post_id = models.ForeignKey(Post, related_name='post_id', on_delete=models.CASCADE)
def __str__(self):
return "%s %s" % (self.user_id, self.post_id)
#serializers.py
class LikeSerializer(serializers.ModelSerializer):
class Meta:
fields= (
'user_id',
'post_id'
)
model = Like
Спасибо
Вы можете использовать F()
только при выполнении запросов.
post = Post.objects.get(id=post_id)
post.likes = post.likes + 1
post.save()
или если вы не против сделать еще один запрос, но также убедиться, что пост всегда имеет нужное количество лайков:
post = Post.objects.get(id=post_id)
post.likes = Like.objects.filter(post=post).count()
post.save()
Основной причиной того, что лайки не обновлялись, было то, что в LikeView вы написали
def like(self, request, format=None):
вместо
def post(self, request, *args, **kwargs):
Обновите представление следующим образом:
class LikeView(generics.CreateAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
queryset = Like.objects.all()
serializer_class = LikeSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
if (serializer.is_valid()):
like = serializer.save()
post = like.post_id
post.likes = post.post_id.count()
post.save()
return Response(LikeSerializer(like).data,
status=status.HTTP_200_OK)
return Response(serializer.errors(),
status=status.HTTP_400_BAD_REQUEST)
В приведенном выше коде вы сохранили объект Like в переменную like
.
Затем получили объект post и нашли count, используя related name
внешний ключ post.
Дополнительно, структура вашей модели позволяет одному пользователю несколько раз понравиться одному сообщению. Чтобы предотвратить это, вы можете добавить уникальное сочетание в модель Likes.
class Like(models.Model):
user_id = models.ForeignKey(User, related_name='user_id', on_delete=models.CASCADE)
post_id = models.ForeignKey(Post, related_name='post_id', on_delete=models.CASCADE)
def __str__(self):
return "%s %s" % (self.user_id, self.post_id)
class Meta:
unique_together = ('user_id', 'post_id',)