DetailView从Django在NextJS 13中(获取数据)

huangapple go评论85阅读模式
英文:

DetailView from Django in NextJS 13 (fetching data)

问题

我有一个基于Django的后端应用程序,以及一个前端使用NextJS的应用程序。在我的Django应用程序中,我有一个名为Post的模型,其中包含两个视图 - PostDetailViewPostListView

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.pyurls.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[&#39;content_type&#39;] = &#39;application/json&#39;
    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 = &#39;__all__&#39;

#urls.py
from django.contrib import admin
from django.urls import include, path

from . import views

urlpatterns = [
path(&#39;api/posts/&#39;, views.PostListView.as_view(), name=&#39;post-list&#39;),
path(&#39;api/posts/&lt;int:pk&gt;/&#39;, views.PostDetailView.as_view(), name=&#39;post-detail&#39;),
]

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 &#39;ListView&#39;)
-- [id]
--- page.tsx (here is my &#39;DetailView&#39;)

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 = () =&gt; {
const [posts, setPosts] = useState&lt;Post[]&gt;([]);

useEffect(() =&gt; {
 fetchData();
}, []);

 const fetchData = async () =&gt; {
    try {
     const response: AxiosResponse&lt;Post[]&gt; = await axios.get(&#39;http://127.0.0.1:8000/blog/api/posts/&#39;);
     const data: Post[] = response.data;
     setPosts(data);
   } catch (error) {
     console.error(&#39;Error fetching data:&#39;, 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 &#39;react&#39;;
import axios, { AxiosResponse } from &#39;axios&#39;;
import { usePathname, useRouter, useSearchParams } from &#39;next/navigation&#39;;

interface Post {
  id: number;
  title: string;
  image_url: string | null;
  content: string;
}

const PostDetail: React.FC = () =&gt; {
  const [post, setPost] = useState&lt;Post | null&gt;(null);

  const searchParams = useSearchParams()
  const id = searchParams.get(&#39;&#39;)

  const fetchData = async () =&gt; {
    try {
      const response: AxiosResponse&lt;Post&gt; = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
      const data: Post = response.data;
      setPost(data);
    } catch (error) {
      console.error(&#39;Error fetching data:&#39;, error);
    }
  };

  fetchData();

  if (!post) {
    return &lt;div&gt;Loading...&lt;/div&gt;;
  }

  return (
    &lt;div&gt;
      &lt;h1 className=&#39;font-6xl font-red-800&#39;&gt;{post.title}&lt;/h1&gt;
        &lt;/div&gt;
  );
};

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 &#39;react&#39;;
import axios, { AxiosResponse } from &#39;axios&#39;;
import { useRouter } from &#39;next/router&#39;;

interface Post {
  id: number;
  title: string;
  image_url: string | null;
  content: string;
}

const PostDetail: React.FC = () =&gt; {
  const [post, setPost] = useState&lt;Post | null&gt;(null);
  const router = useRouter();
  const { id } = router.query;

  useEffect(() =&gt; {
    if (id) {
      fetchData();
    }
  }, [id]);

  const fetchData = async () =&gt; {
    try {
      const response: AxiosResponse&lt;Post&gt; = 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 &lt;div&gt;Loading...&lt;/div&gt;;
  }

  return (
    &lt;div&gt;
      &lt;h1 className=&#39;font-6xl font-red-800&#39;&gt;{post.title}&lt;/h1&gt;      
    &lt;/div&gt;
  );
};

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&lt;Post | null&gt;(null);
const pathname = usePathname();
const id = pathname.split(&#39;/&#39;).pop();

useEffect(() =&gt; {
if (id) {
  fetchData();
}
}, [id]);

const fetchData = async () =&gt; {
try {
  const response: AxiosResponse&lt;Post&gt; = await axios.get(`http://127.0.0.1:8000/blog/api/posts/${id}/`);
  const data: Post = response.data;
  setPost(data);
} catch (error) {}
};

huangapple
  • 本文由 发表于 2023年7月23日 22:16:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76748706.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定