Django+React全棧開發:動態字段

詳情組件

以前咱們編寫了ArticleDetail這個組件,不過它目前只能顯示article+ID這樣一串文本,讓咱們修改代碼,讓這個組件顯示實際的文章內容吧。javascript

首先目前咱們點擊首頁的文章標題,指向的url爲articles/id/,這與咱們後端的url重複了。爲此,更改一下backend/urls.py前端

urlpatterns = [
    path('admin/', admin.site.urls),
    # 全都放到api這個路徑後面
    path('api/', include('article.urls')),
    path('auth/', include('rest_framework_social_oauth2.urls')),
]

注意以前ArticleList組件中請求API的地方要作出修改哦java

接着修改ArticleDetail.jspython

import React, {useEffect, useState} from "react";
import { useParams } from 'react-router-dom';

const ArticleDetail = () => {
  // HOOK
  const { articleId } = useParams();
  const [loading, setLoading] = useState(true);
  const [article, setArticle] = useState({});
  const fetchArticle = () => {
    fetch(`/api/articles/${articleId}/`)
      .then(response => response.json())
      .then(result => {
        setArticle(result);
        setLoading(false);
      })
      .catch(e => console.log(e));
  }
  useEffect(fetchArticle, [])

  return (
    loading
    ?
    <div>加載中...</div>
    :
    <div>
      <h4>{article.title}</h4>
      <p>{article.body}</p>
    </div>
  )
}

export default ArticleDetail

代碼很爛,僅供參考。以前咱們講過類組件,只有類組件有生命週期,有state,可是如今React有了HOOK這一功能,看咱們的代碼中,以use開頭的地方,都是HOOKreact

useState使函數組件能夠像類組件同樣使用state,它使用一個參數做爲初始值,並返回一個數組,例如代碼中第7行loading部分,咱們給了名爲loadingstate初始值false,返回的數組中第一個元素是loading這個state,而第二個則是一個函數,能夠用於更改state值。git

以後咱們定義一個獲取文章的函數,獲取結果後設置article,並將loading狀態設爲falseuseEffect則相似類組件的componentDidMount這個生命週期函數,在組件掛載後,將會執行經過參數傳遞的回調函數,獲取文章數據。第二個參數[]使得這個函數只在組件掛載後運行一次。github

有關HOOK的詳情能夠去看React官方文檔。json

返回值部分的JSX就不說了,只是三元運算符根據loading狀態作條件渲染,沒有特別的地方。後端

動態字段

剛剛這個詳情頁面,其實主要是爲了說明一種狀況,對於後端定義的API,並非在任何地方都須要所有數據的。例如,在首頁咱們只須要文章標題、發佈時間,詳情頁才顯示文章內容。儘管如今硬件條件愈來愈好,但若是把全部數據都經過網絡傳輸到客戶端,無疑是對網絡資源的浪費api

不過若是爲前端不一樣頁面定義不一樣的序列化器或者修改模型那就太麻煩了,咱們能夠經過定義請求中的參數如fields=xx,xxx來實現這一點,已經有一個好用的第三方庫幫咱們作到啦。那就是drf-flex-fields,讓咱們使用pip來安裝:

$ pip install drf-flex-fields

要使用也很是簡單,只須要修改article/serializers.py

from rest_flex_fields import FlexFieldsModelSerializer
from article.models import Article
from rest_framework import serializers


class ArticleSerializer(FlexFieldsModelSerializer):
    author = serializers.ReadOnlyField(source='author.username')

    class Meta:
        model = Article
        fields = ['id', 'author', 'title', 'body', 'created', 'updated']

用命令行測試一下:

$ http http://127.0.0.1:8000/api/articles/\?fields\=author,body
...
[
    {
        "author": "elliot",
        "body": "時間測試"
    },
    {
        "author": "elliot",
        "body": "如今是4月5日11點10分"
    }
]

 $ http http://127.0.0.1:8000/api/articles/\?omit\=author,body  
...

[
    {
        "created": "2020-04-05T11:47:49.087547+08:00",
        "id": 2,
        "title": "如今時間",
        "updated": "2020-04-05T11:47:49.087580+08:00"
    },
    {
        "created": "2020-04-05T11:10:56.880622+08:00",
        "id": 1,
        "title": "第一天",
        "updated": "2020-04-05T11:10:56.880674+08:00"
    }
]

既能夠經過fields參數來指定須要的字段,也能夠經過omit來指定要排除哪些字段。注意url中參數要用問號?開頭,在命令行中則要用\?來轉義問號。

這時候能夠去修改前端代碼:

......
const ArticleItem = props => (
  <div key={props.item.id}>
    ......
    <p>
      {/* 刪掉這行<strong>{props.item.body}</strong>*/}
      ......
    </p>
  </div>
)

class ArticleList extends Component {
......
  componentDidMount() {
    // 修改這裏
    fetch('/api/articles/?omit=author,body')
      .then(response => response.json())
      .then(result => this.setState({articleList: result}))
      .catch(e => this.setState({error: e}));
  }
......

}
......

效果圖

如今首頁就沒有文章詳細內容了。文章詳情組件就留給讀者本身去修改了。

drf-flex-fields這個庫的功能可不止於此哦,建議讀者去Github看看這個庫的說明與源碼,可使咱們的API便捷的實現關係型字段的聯合查詢。

最後

最近對這個系列的文章有些思考,在這裏不打算一步一步作一個實際的,或者說好看的,優雅的博客系統,而是想到一些功能,儘可能加上去,實踐DjangoReact的結合,若是有讀者但願我實現什麼功能,能夠在公衆號留言,最終咱們可能會作出一個很奇葩的應用,哈哈。若是想要直接複製代碼作一個我的博客,能夠參考個人我的博客,Github地址:https://github.com/Eliot00/el...


歡迎關注個人公衆號「公子政的宅平常」,原創技術文章第一時間推送。

二維碼

相關文章
相關標籤/搜索