英文:
DetailView from Django in NextJS 13 (fetching data)
问题
我有一个基于Django的后端应用程序,以及一个前端使用NextJS的应用程序。在我的Django应用程序中,我有一个名为Post
的模型,其中包含两个视图 - PostDetailView
和 PostListView
。
from django.shortcuts import get_object_or_404
from django.template import TemplateDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Post
from .serializers import PostSerializer
from rest_framework.renderers import JSONRenderer
from django.http import Http404, HttpResponse
class JSONResponse(HttpResponse):
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
class PostListView(APIView):
def get(self, request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return JSONResponse(serializer.data)
class PostDetailView(APIView):
def get(self, request, pk):
try:
post = Post.objects.get(pk=pk)
serializer = PostSerializer(post)
return Response(serializer.data, status=status.HTTP_200_OK)
except Post.DoesNotExist:
raise Http404
我还设置了serializers.py
和urls.py
。
# serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
# urls.py
from django.contrib import admin
from django.urls import include, path
from . import views
urlpatterns = [
path('api/posts/', views.PostListView.as_view(), name='post-list'),
path('api/posts/<int:pk>/', views.PostDetailView.as_view(), name='post-detail'),
]
在我的NextJS应用程序中,我正在使用一种新的文件夹结构,位于src/app
。这是我的文件夹结构。
- src/app
-- blog
--- page.tsx (这是我的 'ListView')
-- [id]
--- page.tsx (这是我的 'DetailView')
我的ListView运行良好,它显示了所有对象。
interface Post {
id: number;
title: string;
image_url: string | null;
content: string;
}
const PostsList: React.FC = () => {
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
try {
const response: AxiosResponse<Post[]> = await axios.get('http://127.0.0.1:8000/blog/api/posts/');
const data: Post[] = response.data;
setPosts(data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
return (
// 返回你的ListView组件部分
);
};
但是我在DetailView中遇到了问题。我不知道如何显示它。你有解决这个问题的方法吗?
在本地主机上,我的链接如下:
#Django (rest API)
List View: http://127.0.0.1:8000/blog/api/posts/
Detail View: http://127.0.0.1:8000/blog/api/posts/2/(其中2是我的帖子ID)
#NextJS
List View: http://127.0.0.1:3000/blog
Detail View: http://127.0.0.1:3000/blog/2(其中2是我的帖子ID)
我尝试了类似于这样的东西,不幸的是它只显示“Loading...”,这是我无法获取数据的信息。
import React, { useEffect, useState } from 'react';
import axios, { AxiosResponse } from 'axios';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
interface Post {
id: number;
title: string;
image_url: string | null;
content: string;
}
const PostDetail: React.FC = () => {
const [post, setPost] = useState<Post | null>(null);
const searchParams = useSearchParams()
const id = searchParams.get('')
const fetchData = async () => {
try {
const response: AxiosResponse<Post> = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
const data: Post = response.data;
setPost(data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
if (!post) {
return <div>Loading...</div>;
}
return (
// 返回你的DetailView组件部分
);
};
export default PostDetail;
希望这些部分对你有所帮助。
英文:
I've got Django based app as my back-end, and NextJS as front-end. I've got a Post model in my Django App with two views - PostDetailView
and PostListView
.
from django.shortcuts import get_object_or_404
from django.template import TemplateDoesNotExist
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Post
from .serializers import PostSerializer
from rest_framework.renderers import JSONRenderer
from django.http import Http404, HttpResponse
class JSONResponse(HttpResponse):
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
class PostListView(APIView):
def get(self, request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return JSONResponse(serializer.data)
class PostDetailView(APIView):
def get(self, request, pk):
try:
post = Post.objects.get(pk=pk)
serializer = PostSerializer(post)
return Response(serializer.data, status=status.HTTP_200_OK)
except Post.DoesNotExist:
raise Http404
I've also set up serializers.py and urls.py.
#serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
#urls.py
from django.contrib import admin
from django.urls import include, path
from . import views
urlpatterns = [
path('api/posts/', views.PostListView.as_view(), name='post-list'),
path('api/posts/<int:pk>/', views.PostDetailView.as_view(), name='post-detail'),
]
In my NextJS App I'm using new approach for folder structure with src/app. This is my folder structure.
- src/app
-- blog
--- page.tsx (here is my 'ListView')
-- [id]
--- page.tsx (here is my 'DetailView')
My ListView works fine, it displays all my objects.
interface Post {
id: number;
title: string;
image_url: string | null;
content: string;
}
const PostsList: React.FC = () => {
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
try {
const response: AxiosResponse<Post[]> = await axios.get('http://127.0.0.1:8000/blog/api/posts/');
const data: Post[] = response.data;
setPosts(data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
return (
But I've got a problem with my DetailView. I don't know how display this. Have you got any solutions for this?
On local host my link look like this:
#Django (rest API)
List View: http://127.0.0.1:8000/blog/api/posts/
Detail View: http://127.0.0.1:8000/blog/api/posts/2/ (where 2 is ID for my post)
#NextJS
List View: http://127.0.0.1:3000/blog
Detail View: http://127.0.0.1:3000/blog/2 (where 2 is ID form my post
I've tried with something like this, unfortunetly it displays only 'Loading...' which is my info for bad fetching.
import React, { useEffect, useState } from 'react';
import axios, { AxiosResponse } from 'axios';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
interface Post {
id: number;
title: string;
image_url: string | null;
content: string;
}
const PostDetail: React.FC = () => {
const [post, setPost] = useState<Post | null>(null);
const searchParams = useSearchParams()
const id = searchParams.get('')
const fetchData = async () => {
try {
const response: AxiosResponse<Post> = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
const data: Post = response.data;
setPost(data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
if (!post) {
return <div>Loading...</div>;
}
return (
<div>
<h1 className='font-6xl font-red-800'>{post.title}</h1>
</div>
);
};
export default PostDetail;
答案1
得分: 0
你正在从Next.js的URL中获取帖子ID。由于你正在使用文件结构[id]/page.tsx,Next.js将自动在查询参数中填充id值。你可以使用next/router中的useRouter hook从查询参数中获取id:
import React, { useEffect, useState } from 'react';
import axios, { AxiosResponse } from 'axios';
import { useRouter } from 'next/router';
interface Post {
id: number;
title: string;
image_url: string | null;
content: string;
}
const PostDetail: React.FC = () => {
const [post, setPost] = useState<Post | null>(null);
const router = useRouter();
const { id } = router.query;
useEffect(() => {
if (id) {
fetchData();
}
}, [id]);
const fetchData = async () => {
try {
const response: AxiosResponse<Post> = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
const data: Post = response.data;
setPost(data);
} catch (error) {
}
};
if (!post) {
return <div>Loading...</div>;
}
return (
<div>
<h1 className='font-6xl font-red-800'>{post.title}</h1>
</div>
);
};
export default PostDetail;
请注意,这是你提供的代码的中文翻译。
英文:
You are getting the post ID from the URL in Next.js. Since you are using the file structure [id]/page.tsx, Next.js will automatically populate the id value in the query parameter. You can get the id from the query parameter with useRouter hook from next/router:
import React, { useEffect, useState } from 'react';
import axios, { AxiosResponse } from 'axios';
import { useRouter } from 'next/router';
interface Post {
id: number;
title: string;
image_url: string | null;
content: string;
}
const PostDetail: React.FC = () => {
const [post, setPost] = useState<Post | null>(null);
const router = useRouter();
const { id } = router.query;
useEffect(() => {
if (id) {
fetchData();
}
}, [id]);
const fetchData = async () => {
try {
const response: AxiosResponse<Post> = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
const data: Post = response.data;
setPost(data);
} catch (error) {
}
};
if (!post) {
return <div>Loading...</div>;
}
return (
<div>
<h1 className='font-6xl font-red-800'>{post.title}</h1>
</div>
);
};
export default PostDetail;
答案2
得分: 0
I've found solutions for this one.
const [post, setPost] = useState<Post | null>(null);
const pathname = usePathname();
const id = pathname.split('/').pop();
useEffect(() => {
if (id) {
fetchData();
}
}, [id]);
const fetchData = async () => {
try {
const response: AxiosResponse<Post> = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
const data: Post = response.data;
setPost(data);
} catch (error) {}
};
(Note: The code is provided without translation as per your request.)
英文:
I've found solutions for this one.
const [post, setPost] = useState<Post | null>(null);
const pathname = usePathname();
const id = pathname.split('/').pop();
useEffect(() => {
if (id) {
fetchData();
}
}, [id]);
const fetchData = async () => {
try {
const response: AxiosResponse<Post> = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
const data: Post = response.data;
setPost(data);
} catch (error) {}
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论