專案完成小結:使用DjangoStarter v3和Taro開發的微信小程式

程序设计实验室發表於2024-09-12

前言

不知不覺已經九月了,又到了一年的開學季,我每年都想做的專案牆甚至連個影子都沒有…😂

最近生活中的瑣事太多了,導致完全沒有想寫文章的動力,不過再怎麼拖還是得記錄,隨便寫寫吧~

這次是7月份的一個小專案,談不上什麼技術含量,算是友情開發了。後端 DjangoStarter v3,前端使用 Taro 做微信小程式。

事實上後端基本沒啥好說的,基本有什麼坑能記錄的都在小程式這塊,不得不說微信真是史中史,不僅程式碼寫得跟答辯一樣,文件更是一坨😂

之前看網上有個說法,正因為微信做得跟答辯一樣,才給了小程式開發者一道護城河,現在想起來還蠻有道理的,哈哈哈😃

後端部分

先來說說後端部分吧

自從有了 DjangoStarter ,這類小專案的後端開發已經直接秒了

這個專案裡用到幾個新的,我之前有寫文章介紹了,直接放連結吧~

  • Django裡整合騰訊COS物件儲存
  • 使用 django-treebeard 編輯類別

使用 django-filer 管理檔案

忘了這個還沒寫文章,那麼簡單介紹一下吧,這個元件可以實現檔案(包括圖片)的集中管理,還提供了 admin 介面,不過UI風格就比較原始了,而且中文locale還有bug,得手動修改才能正常切換到中文。不過對於這個專案來說是夠用的

專案地址: https://github.com/django-cms/django-filer

安裝: pdm add django-filer

filer 新增到 INSTALLED_APPS

新增 src/config/settings/components/filer.py 配置

THUMBNAIL_PROCESSORS = (
    'easy_thumbnails.processors.colorspace',
    'easy_thumbnails.processors.autocrop',
    'easy_thumbnails.processors.scale_and_crop',
    # Subject location aware cropping
    # 'filer.thumbnail_processors.scale_and_crop_with_subject_location',
    'easy_thumbnails.processors.filters',
)

FILER_ENABLE_LOGGING = True

最後修改一下需要用到附件的欄位

from filer.fields.image import FilerImageField

class Brand(ModelExt):
    name = models.CharField('名稱', max_length=100)
    # logo = models.ImageField(upload_to='brand_logos/')
    logo = FilerImageField(
        verbose_name='Logo', null=True, blank=True,
        related_name='+', on_delete=models.SET_NULL,
    )

大概就這樣,具體用法看官方文件吧~

使用 ninja 來編寫API

DjangoStarter v3 開始從drf 切換到 ninja

這個 ninja 和 FastAPI 非常像,寫起來比 drf 舒服多了,雖然不能像 drf 一樣自動生成 crud 介面,不過寫起來也多不了多少程式碼,而且更加靈活。

(PS:DjangoStarter v3 依然支援自動生成 crud 介面,同時還可以使用第三方庫來實現自動生成基於 ninja 的 crud 介面,不過我還沒用過,可以參考下面的擴充套件部分)

比如上面說的 django-filer 庫,圖片欄位其實是指向 filer.fields.models.File 模型的外來鍵,所以介面如果沒做處理,生成出來的資料就只是一個外來鍵ID而已,所以要修改一下 schema

class CaseOut(ModelSchema):
  cover_image: str

  @staticmethod
  def resolve_cover_image(obj: Case):
    if not obj.cover_image:
      return f'https://starblog/Api/PicLib/Random/{obj.id}/250/150'
    return obj.cover_image.url

  class Meta:
    model = Case
    fields = [
      'id', 'is_deleted', 'created_time', 'updated_time', 'name', 'description',
      'category', 'car_model', 'part', 'build_time',
    ]

以上程式碼會把 cover_image 欄位渲染為一個圖片地址,如果 cover_image 不存在的話,則返回一個隨機圖片地址。

schema 實現了邏輯和資料渲染分開,程式碼結構更清晰。

還可以實現更復雜的邏輯,只需要實現 resolve_欄位名 方法就行。

ninja 生態擴充套件

我也是最近才發現的,原來 django-ninja 還有個中文網,裡面寫了幾個 ninja 生態的擴充套件,感覺都挺不錯的,以後有空可以試試。

網址: https://django-ninja.cn/

  • Ninja JWT - 一個用於 Django Ninja REST 框架的 JSON Web 令牌認證外掛。
  • Django Ninja Extra - Django Ninja Extra 提供了一種 基於類 的方法以及額外的功能,這將使用 Django Ninja 加速您的 RESTful API 開發。
  • Django Ninja CRUD - Django Ninja CRUD 是一個強大的、宣告式的、但又有點固執己見的框架,它簡化了使用 Django Ninja 開發 CRUD(建立、讀取、更新、刪除)端點的過程,並且還提供了一種宣告式的基於場景的方法,用於使用 Django REST Testing(這個包的小弟)測試這些端點。

小程式部分

這次依然使用 Taro 來開發移動端,上次是做 H5(公眾號),這次試試 Taro 做出來的小程式咋樣,實際效果還行。

狀態管理依然選擇了 mobx ,用習慣了,前端輪子太多,懶得去試用其他的了~

相比起後端部分,小程式能寫的東西會多一點點(但也不多,都很簡單)

在Taro裡使用tailwindcss

最近我開始使用 tailwindcss ,一下就喜歡上這種高效的樣式工具(雖然會有很長的一串class)不過瑕不掩瑜,使用 tailwindcss 可以很方便在網路上 copy 各種樣式,還能讓 LLM 幫我寫各種樣式,生產力拉滿了~

Taro 官方提供了 tailwindcss 的支援,這點非常好,跟著官方文件來就行

詳見官方文件: https://docs.taro.zone/docs/tailwindcss

分享小程式

如果不主動呼叫,那麼只有註冊了 onShareAppMessage 事件,才能在點右上角三個點的時候,顯示轉發按鈕;同樣的,註冊了 onShareTimeline 事件才能分享到朋友圈。

相應的,Taro 裡提供了這倆事件的 hook ,直接看程式碼

import Taro, {useShareAppMessage, useShareTimeline} from '@tarojs/taro'

const CasePage = () => {   
  const getCase = async () => {
    if (!id) return
    const data = await CaseService.get(Number(id))
    console.log('get case', data)
    setCaseData(data.data)
    return {
      title: `案例:${data.data.name}`,
      path: RouterMap.car.case(data.data.id),
      imageUrl: data.data.cover_image
    }
  }

  useShareAppMessage(res => {
    console.log('執行分享操作', res)
    return {
      title: '案例分享',
      path: RouterMap.index,
      promise: new Promise(resolve => getCase().then((data) => {
        // @ts-ignore
        resolve(data)
      })),
    }
  })

  useShareTimeline(() => {
    console.log('執行分享朋友圈操作')

    return {
      title: `案例:${caseData.name}`,
      query: `id=${caseData.id}`,
      imageUrl: caseData.cover_image
    }
  })
}

跟小程式文件裡說的一樣的,需要返回的引數啥的也一樣,所以直接看文件吧~

主動分享

主動分享的話,只要把按鈕設定成 share 型別就行,Taro 同樣做了包裝。

<Button type='info' icon={<Share/>} openType='share'>分享</Button>

參考資料

  • https://juejin.cn/post/7261774602481369147
  • https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
  • https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html#onShareAppMessage-Object-object

使用者登入

本專案中我是做一個單獨的頁面來處理登入,也可以用 Modal 的形式,不過一開始我還對獲取使用者資訊抱有幻想,因為文件介紹獲取使用者頭像、暱稱等資訊需要主動觸發才行,所以放在一個單獨的頁面,提供一個登入按鈕,讓使用者去點選。

不過後面發現新版本的小程式已經不能用這種方式獲取資訊了……

登入這塊 Taro 也封裝好了,其實就是把 wx.login 的 wx 改成 Taro 而已

const LoginPage = observer(() => {
  const handleLogin = async (data: LoginToken) => {
    UserStore.login({
      token: data.token,
      exp: String(data.exp),
    })

    const userInfo = await AccountService.getCurrentUser()
    console.log('獲取使用者資訊', userInfo)
    UserStore.userInfo = userInfo.data
    Taro.navigateBack()
  }

  const autoLogin = async () => {
    Taro.showToast({title: '正在登入', icon: 'loading'})
    Taro.login({
      success: async (res) => {
        if (res.code) {
          console.log('小程式登入,獲取code', res.code)
          const resp = await AccountService.loginWeApp(res.code)
          console.log('小程式登入,請求後端', resp)
          await handleLogin(resp.data)
        } else {
          console.log('登入失敗!', res.errMsg)
        }
      }
    })
  }
}

拿到小程式 OAuth 之後的 code,呼叫後端介面登入,搞定。

而且這部分 DjangoStarter v3 也整合了🕶

點選圖片開啟大圖

在圖片元件的 onTap 事件裡呼叫 Taro.previewImage 就行,記得把大圖的地址傳入(如果小圖是單獨的地址的話)

<Image
  key={e.id} src={e.url}
  onTap={() => {
    Taro.previewImage({
      current: e.url,
      urls: caseData.images.map(i => i.url)
    })
  }}
  className="w-full rounded shadow"
  mode="aspectFill"
/>

部署

這次的部署也是船新版本

這個專案也算是新版 DjangoStarter 的第一次實踐,所以遇到一些坑,我都寫了部落格記錄了

  • 在python專案的docker映象裡使用pdm管理依賴
  • 新版的Django Docker部署方案,多階段構建、自動處理前端依賴
  • 使用python-slim映象遇到無法使用PostgreSQL的問題

總得來說 daphne 伺服器用著還不錯。

小結

開頭就說了,本次專案的算是比較簡單的,時間主要花在前端的互動和一些細節的調整上

Taro 用來開發小程式還是絲滑的,意料中打包和釋出可能遇到的問題,實際上都沒有

這篇小結真的拖了太久了,我也好久沒寫程式碼了… 得抓緊時間整理思緒,然後把想做的東西都搞起來了。

相關文章