字段"_id"期望一个数字,但在 Django Rest 框架中得到了"top"



我已经在这里看到了这类问题,但我无法重现解决方案。我正试图从我的模型中获得与其评级相关的热门博客文章。

#models.py
class BlogPost(models.Model):
_id = models.AutoField(primary_key=True, editable=False)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
title = models.CharField(max_length=100, null=True, blank=True)
image = models.ImageField(null=True, blank=True,
default='/placeholder.png' )


description = models.TextField(null=True, blank=True, help_text="Description Here ")
rating = models.DecimalField(
max_digits=7, decimal_places=2, null=True, blank=True)
numReviews = models.IntegerField(null=True, blank=True, default=0)
createdAt = models.DateTimeField(auto_now_add=True)


def __str__(self):
return str(self.createdAt)
class BlogPostReview(models.Model):
blogpost = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, null=True, blank=True)
rating = models.IntegerField(null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
_id = models.AutoField(primary_key=True, editable=False)
def __str__(self):
return str(self.rating)

序列化程序

#serializers.py
class BlogPostReviewSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPostReview
fields = '__all__'
class BlogPostSerializer(serializers.ModelSerializer):
reviews = BlogPostReviewSerializer( many=True, read_only=True)
class Meta:
model = BlogPost
fields = '__all__'
def get_reviews(self, obj):
reviews = obj.blogpostreview_set.all()
serializer = BlogPostReviewSerializer(reviews, many=True)
return serializer.data

现在进入视图。。。问题一

from django.shortcuts import render
# Create your views here.
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import BlogPost, BlogPostReview 
from .serializers import BlogPostSerializer
@api_view(['GET'])
def getBlogPosts(request):
query = request.query_params.get('keyword')
if query == None:
query = ''
blogposts = BlogPost.objects.filter(
title__icontains=query).order_by('-createdAt')
page = request.query_params.get('page')
paginator = Paginator(blogposts, 8)
try:
blogposts = paginator.page(page)
except PageNotAnInteger:
blogposts = paginator.page(1)
except EmptyPage:
blogposts = paginator.page(paginator.num_pages)
if page == None:
page = 1
page = int(page)

serializer = BlogPostSerializer(blogposts, many=True)
return Response({'blogposts': serializer.data, 'page': page, 'pages': paginator.num_pages})
@api_view(['GET'])
def getTopBlogPosts(request):
blogposts = BlogPost.objects.filter(rating__gte=4.0).order_by('-rating')[0:10]
serializer = BlogPostSerializer(blogposts, many=True)
return Response(serializer.data)

@api_view(['GET'])
def getBlogPost(request, pk):
blogpost = BlogPost.objects.get(_id=pk)
serializer = BlogPostSerializer(blogpost, many=False)
return Response(serializer.data)

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def createBlogPostReview(request, pk):
user = request.user
blogpost = BlogPost.objects.get(_id=pk)
data = request.data
# 1 - Review already exists
alreadyExists = blogpost.review_set.filter(user=user).exists()
if alreadyExists:
content = {'detail': 'Product already reviewed'}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
# 2 - No Rating or 0
elif data['rating'] == 0:
content = {'detail': 'Please select a rating'}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
# 3 - Create review
else:
review = BlogPostReview.objects.create(
user=user,
blogpost=blogpost,
name=user.first_name,
rating=data['rating'],
comment=data['comment'],
)
reviews = blogpost.review_set.all()
blogpost.numReviews = len(reviews)
total = 0
for i in reviews:
total += i.rating
blogpost.rating = total / len(reviews)
blogpost.save()
return Response('Review Added')

URL

来自django.url的导入路径从…起将视图导入为视图

url模式=[

path('', views.getBlogPosts, name="blogposts"),
path('<str:pk>/', views.getBlogPost, name="blogpost"),
path('top/', views.getTopBlogPosts, name='top-blogposts'),
path('<str:pk>/reviews/', views.createBlogPostReview, name="create-review"),

]

当我试图加载顶部的帖子时,这个错误来了

[21/Jun/2021 21:27:43] "GET /api/blog/top/ HTTP/1.1" 500 165476
[21/Jun/2021 21:27:48] "GET /api/blog/ HTTP/1.1" 200 5256
Internal Server Error: /api/blog/top/
Traceback (most recent call last):
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsfields__init__.py", line 1823, in get_prep_value
return int(value)
ValueError: invalid literal for int() with base 10: 'top'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangocorehandlersexception.py", line 47, in inner
response = get_response(request)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangocorehandlersbase.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangoviewsdecoratorscsrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangoviewsgenericbase.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesrest_frameworkviews.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesrest_frameworkviews.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesrest_frameworkviews.py", line 480, in raise_uncaught_exception
raise exc
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesrest_frameworkviews.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesrest_frameworkdecorators.py", line 50, in handler
return func(*args, **kwargs)
File "E:eCommerce_Projectsremote-hospitalblogviews.py", line 48, in getBlogPost
blogpost = BlogPost.objects.get(_id=pk)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsmanager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsquery.py", line 424, in get
clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsquery.py", line 941, in filter
return self._filter_or_exclude(False, args, kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsquery.py", line 961, in _filter_or_exclude
clone._filter_or_exclude_inplace(negate, args, kwargs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsquery.py", line 968, in _filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelssqlquery.py", line 1396, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelssqlquery.py", line 1415, in _add_q
child_clause, needed_inner = self.build_filter(
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelssqlquery.py", line 1350, in build_filter
condition = self.build_lookup(lookups, col, value)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelssqlquery.py", line 1196, in build_lookup
lookup = lookup_class(lhs, rhs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelslookups.py", line 25, in __init__
self.rhs = self.get_prep_lookup()
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelslookups.py", line 77, in get_prep_lookup
return self.lhs.output_field.get_prep_value(self.rhs)
File "C:UsersLENOVOAppDataLocalProgramsPythonPython39libsite-packagesdjangodbmodelsfields__init__.py", line 1825, in get_prep_value
raise e.__class__(
ValueError: Field '_id' expected a number but got 'top'.
[21/Jun/2021 21:27:55] "GET /api/blog/top/ HTTP/1.1" 500 165476

需要帮助来删除这个错误以及实现这个功能的任何其他方法,以及我在这个代码中做错了什么。

我将发布您的解决方案以及对代码的一些想法。

主要问题

views.py


@api_view(['GET'])
def getBlogPost(request, pk):
blogpost = BlogPost.objects.get(_id=pk) ## << HERE >> ##
serializer = BlogPostSerializer(blogpost, many=False)
return Response(serializer.data)

urls.py


path('', views.getBlogPosts, name="blogposts"),
path('<str:pk>/', views.getBlogPost, name="blogpost"), ## << HERE >> ##
path('top/', views.getTopBlogPosts, name='top-blogposts'),
path('<str:pk>/reviews/', views.createBlogPostReview, name="create-review"), ## << SAME PROBLEM HERE >> ##

在简历中,您试图将类型传递为pk-wwitch是您的模型BlogPost的_id,并且是一个AutoField。也许从ot改过来就能解决问题。

Extras

  1. 不知道是否有型号。AutoField是保存Id值的最佳方法。通常我会使用类似UUID字段的东西
  2. 通常情况下,如果您的a使用一些必要且可重复使用的字段,例如:id、created_at、updated_at等。一种方法是创建一个BaseModel,通常在您的project.core应用程序中实现。并通过继承将其用作模型,如下所示:

core.models.py

class BaseModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField()
updated_at = models.DateTimeField()
#
# Continue your BaseModel
#

在你的型号中

class BlogPostReview(BaseModel):
blogpost = models.ForeignKey(BlogPost, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, null=True, blank=True)
rating = models.IntegerField(null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)

def __str__(self):
return str(self.rating)
  1. 改进视图的一个好方法是使用基于类的视图
  2. 一种巧妙的获取和过滤方法,例如:
BlogPostReview.objects.get(id=pk) 
BlogPostReview.objects.filter(id=pk) 

使用了一个通用的筛选器类,在中实现,几乎像一个序列化程序类,并且可以很好地与基于类的视图配合使用。通用过滤器

最新更新