Django Rest Framework с shortuuid, generics.RetrieveUpdateDestroyAPIView возвращает 404 {"detail": "Не найдено."}
Я переделывал сайт социальной сети, дорабатывая Django и фреймворк rest, я не хотел использовать стандартный линейный подсчет id в django и мне не нравилось, насколько длинными были id в библиотеке uuid, поэтому я использовал библиотеку shortuuid. Я использовал их для постов и комментариев, просто чтобы сохранить анонимность подсчета как постов, так и комментариев. На стороне постов все работает для CRUD вещей (что должно быть доказательством того, что проблема не от библиотеки shortuuid, насколько я знаю), хотя с комментариями Create Retrieve работает отлично, но Update Destroy не работает. Итак, вот код, с которым мы работаем:
начинаем с моделей, чтобы знать, с какими данными мы работаем (models.py):
from shortuuid.django_fields import ShortUUIDField
... # posts likes etc
class Comment(models.Model):
id = ShortUUIDField(primary_key=True, length=8, max_length=10)
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=350)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ['created']
def __str__(self):
return f'on {self.post} by {self.user}'
objects = models.Manager()
serializers.py:
class CommentSerializer(ModelSerializer):
username = SerializerMethodField()
def get_username(self, comment):
return str(comment.user)
class Meta:
model = Comment
fields = ['id', 'user', 'post', 'username', 'body', 'created', 'updated']
read_only_fields = ['id', 'post', 'user', 'username']
теперь с маршрутизацией (urls.py):
from django.urls import path
from .views import *
urlpatterns = [
...
path('<str:pk>/comments/' , Comments),
path('<str:pk>/comments/create/', CreateComment),
path('<str:pk>/comments/<str:cm>/', ModifyComment),
# pk = post ID
# cm = comment ID
]
views.py:
class ModifyComment(generics.RetrieveUpdateDestroyAPIView):
serializer_class = CommentSerializer
permission_classes = [permissions.AllowAny]
def get_queryset(self):
post = Post.objects.get(pk=self.kwargs['pk'])
comment = Comment.objects.get(post=post, pk=self.kwargs['cm'])
return comment
def perform_update(self, serializer):
print(Post.objects.all())
post = Post.objects.get(pk=self.kwargs['pk'])
comment = Comment.objects.filter(pk=self.kwargs['cm'], post=post)
if self.request.user != comment.user:
raise ValidationError('you can\'t edit another user\'s post')
if comment.exists():
serializer.save(user=self.request.user, comment=comment)
else:
raise ValidationError('the comment doesnt exist lol')
def delete(self, request, *args, **kwargs):
comment = Comment.objects.filter(user=self.request.user, pk=self.kwargs['cm'])
if comment.exists():
return self.destroy(request, *args, **kwargs)
else:
raise ValidationError("you can\'t delete another user\'s post")
ModifyComment = ModifyComment.as_view()
и в ответ на переход по url '<str:pk>/comments/<str:cm>/'
комментария какого-то поста мы получаем следующее:
Для отдельных объектов необходимо переписать метод get_object.
Вы выполняете запрос GET /str:pk/comments/str:cm/, это вызывает метод retrieve
на представлении, который в свою очередь вызывает get_object
. Поведение по умолчанию - попытка найти объект Comment
с id
равным pk
, поскольку это первый аргумент, поскольку вам нужно фильтровать через другую модель, вам нужно переписать ее.
classy drf - это хороший сайт для просмотра того, как работают внутренние компоненты классов.