Expo React Native 发布方法不包括 Django 休息框架正确路径上的媒体

问题描述 投票:0回答:1

我正在尝试创建一个 Expo React Native 应用程序,我将一个 Pdf 文件发送到我在 Django Rest Framework 中创建的 API。 但是,当我发送 pdf 文件时,它没有保存在正确的位置,我会把代码和日志放在一起更好地解释。

# models.py

from django.db import models


# Create your models here.
class PDFFile(models.Model):
  name = models.CharField(max_length=200, blank=True)
  pdf_file = models.FileField(upload_to="pdfs/", blank=True)

  def __str__(self):
    return str(self.name)
# serializers.py
from rest_framework import serializers
from .models import PDFFile


class PDFFileModelSerializer(serializers.ModelSerializer):
  class Meta:
    model = PDFFile
    fields = ["id", "name", "pdf_file"]
# views.py
from .models import PDFFile
from .serializers import PDFFileModelSerializer

from rest_framework import viewsets, status
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response

class PDFFileViewSet(viewsets.ModelViewSet):
  queryset = PDFFile.objects.all()
  serializer_class = PDFFileModelSerializer
  parser_classes = (MultiPartParser, FormParser)

  def create(self, request, *args, **kwargs):
    name = request.data["name"]
    pdf_file = request.data["pdf_file"]
    print("PDF FILE: ", pdf_file)

    PDFFile.objects.create(name=name, pdf_file=pdf_file)

    return Response("PDF create with success!", status=status.HTTP_200_OK)
  
# urls.py from the app

from rest_framework import routers
from .views import PDFFileViewSet
from django.urls import path, include

router = routers.DefaultRouter()
router.register("pdfs", PDFFileViewSet)

urlpatterns = [
  path("", include(router.urls))
]

# urls.py from the project
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include("pdf_uploader.urls")),
]  + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


# settings.py

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
     )
 }

DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880

STATIC_URL = '/static/'

MEDIA_URL = '/media/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

STATIC_ROOT = BASE_DIR / 'staticfiles'

Expo React Native 组件:

import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, Alert } from 'react-native'
import React, { useState } from 'react'
import * as DocumentPicker from 'expo-document-picker'
import { PDF_BASE_URL } from '../data/api'

const PdfPicker = () => {
  
  const [pdfFile, setPdfFile] = useState(null)
  const [name, setName] = useState("")
  const [uploading, setUploading] = useState(false)
  
  const pickerPdf = async () => {
    let result = await DocumentPicker.getDocumentAsync({
      type: 'application/pdf',
    })
    
    const fileName = result.uri.split('/').pop() // extract the file name from the URI
    const source = { uri: fileName, name: result.name }
    console.log("source", source)
    setPdfFile(source.uri)
    setName(source.name)
  }
  
  const uploadPdfFile = async () => {
    setUploading(true)
    
    const uploadPdf = pdfFile
    const pdfName = name
    const data = new FormData()

    data.append("name", pdfName)
    data.append("pdf_file", uploadPdf)

    const response = await fetch(PDF_BASE_URL + "pdfs/", {
      method: "POST",
      headers: {
        "Content-Type": "multipart/form-data",
      },
      body: data
    })

    console.log("RESULT: ", JSON.stringify(response))

    try {
      await JSON.stringify(response)
    } catch (e) {
      console.log("Catch error:", e)
    }
    setUploading(false)
    Alert.alert(
      "Pdf file uploaded..!!"
    )
    setName("")
    setPdfFile(null)
  }

  return (
    <SafeAreaView style={styles.container} >
      <View>
        <Text style={{color: "white", marginBottom: 30}}>{name}</Text>
      </View>
      <TouchableOpacity style={styles.selectButton} onPress={pickerPdf} >
        <Text style={styles.buttonText}>Pick a Pdf file</Text>
      </TouchableOpacity>
      <View style={styles.pdfContainer}>
        <TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}>
          <Text style={styles.buttonText}>Upload Pdf file</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  )
}

export default PdfPicker

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    backgroundColor: '#000',
    justifyContent: 'center',
  },
  selectButton: {
    borderRadius: 5,
    width: 150,
    height: 50,
    backgroundColor: 'blue',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold'
  },
  pdfContainer: {
    marginTop: 30,
    marginBottom: 50,
    alignItems: 'center',
  },
  uploadButton: {
    borderRadius: 5,
    width: 150,
    height: 50,
    backgroundColor: 'green',
    alignItems: 'center',
    justifyContent: 'center',
  }
})

世博日志

 LOG  RESULT:  {"type":"default","status":200,"ok":true,"statusText":"","headers":{"map":{"allow":"GET, POST, HEAD, OPTIONS","content-length":"26","content-type":"application/json","cross-origin-opener-policy":"same-origin","date":"Thu, 06 Apr 2023 14:19:30 GMT","referrer-policy":"same-origin","server":"railway","vary":"Accept, Origin, Cookie","x-content-type-options":"nosniff","x-frame-options":"DENY"}},"url":"{my.server}/api/pdfs/","bodyUsed":false,"_bodyInit":{"_data":{"size":26,"offset":0,"blobId":"837A79CD-3B4F-4D1C-A15D-74BE46D9CD26","type":"application/json","name":"pdfs.json","__collector":{}}},"_bodyBlob":{"_data":{"size":26,"offset":0,"blobId":"837A79CD-3B4F-4D1C-A15D-74BE46D9CD26","type":"application/json","name":"pdfs.json","__collector":{}}}}

浏览器发送:

{
        "id": 5,
        "name": "livro",
        "pdf_file": "{my.server}/media/pdfs/Stephen.King.-.A.Balsa_WF9W8Kc.pdf"
    }

世博app发送

{
        "id": 4,
        "name": "CERTIDAO-IANDERSONPIZETTEUENDERSONPABLOIII.pdf",
        "pdf_file": "{my.server}/media/C2699748-A1CF-49F5-A3C7-6B527AD3FF44.pdf"
    },

后台日志:

Not Found: /media/C2699748-A1CF-49F5-A3C7-6B527AD3FF44.pdf

所以,我看不出我的问题在哪里。

也许一双新眼睛可以帮助我。

我读过 Django 和 DRF 文档,Expo React Native 文档。 我尝试从 ChatGPT 获得帮助。

现在我想在这里得到一些帮助。

react-native api rest django-rest-framework expo
1个回答
0
投票

我找到了问题的解决方案,我注意到我发送的是移动应用程序发送的 pdf 文件的 blobId,而浏览器发送的是下载的 pdf 文件,所以我开始在移动设备上下载文件应用程序,然后发送到我的后端。

并工作。这是代码。我将与那些遇到与我相同或类似问题的人分享我的解决方案。

import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, Alert } from 'react-native'
import React, { useState } from 'react'
import * as DocumentPicker from 'expo-document-picker'
import { PDF_BASE_URL } from '../data/api'
import * as FileSystem from 'expo-file-system';

const PdfTry = () => {
  const [pdfFileUri, setPdfFileUri] = useState(null)
  const [pdfFileName, setPdfFileName] = useState("")
  const [uploading, setUploading] = useState(false)
  
  const pickerPdf = async () => {
    let result = await DocumentPicker.getDocumentAsync({
      type: 'application/pdf',
      copyToCacheDirectory: false
    })
    
    const pdfUri = result.uri
    const pdfName = result.name

    // Download the selected PDF file to the device's local storage
    const fileUri = FileSystem.documentDirectory + pdfName
    await FileSystem.copyAsync({ from: pdfUri, to: fileUri })
    
    setPdfFileUri(fileUri)
    setPdfFileName(pdfName)
  }
  
  const uploadPdfFile = async () => {
    if (!pdfFileUri) {
      Alert.alert("Please select a PDF file first.")
      return
    }

    setUploading(true)

    const data = new FormData()
    data.append("name", pdfFileName)
    data.append("pdf_file", { uri: pdfFileUri, name: pdfFileName, type: 'application/pdf' })

    const response = await fetch(PDF_BASE_URL + "pdf_upload/", {
      method: "POST",
      headers: {
        "Content-Type": "multipart/form-data",
      },
      body: data
    })

    try {
      await JSON.stringify(response)
    } catch (e) {
      console.log("Catch error:", e)
    }
    setUploading(false)
    Alert.alert(
      "Pdf file uploaded..!!"
    )
    setPdfFileName("")
    setPdfFileUri(null)
  }

  return (
    <SafeAreaView style={styles.container} >
      <View>
        <Text style={{color: "white", marginBottom: 30}}>{pdfFileName}</Text>
      </View>
      <TouchableOpacity style={styles.selectButton} onPress={pickerPdf} >
        <Text style={styles.buttonText}>Pick a Pdf file</Text>
      </TouchableOpacity>
      <View style={styles.pdfContainer}>
        <TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}>
          <Text style={styles.buttonText}>Upload Pdf file</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  )
}

export default PdfTry

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    backgroundColor: '#000',
    justifyContent: 'center',
  },
  selectButton: {
    borderRadius: 5,
    width: 150,
    height: 50,
    backgroundColor: 'blue',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold'
  },
  pdfContainer: {
    marginTop: 30,
    marginBottom: 50,
    alignItems: 'center',
  },
  uploadButton: {
    borderRadius: 5,
    width: 150,
    height: 50,
    backgroundColor: 'green',
    alignItems: 'center',
    justifyContent: 'center',
  }
})

© www.soinside.com 2019 - 2024. All rights reserved.