我正在尝试创建一个 Expo React Native 应用程序,在该应用程序中我将一个 Pdf 文件发送到我在 Django Rest Framework 中创建的 API。但是,当我发送该 pdf 文件时,它并没有保存在正确的位置,我会把它放……
我正在尝试创建一个 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"
}
由 Expo 应用程序发送
{
"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 获取帮助。
现在我正尝试在这里寻求一些帮助。
我找到了我的问题的解决方案,我注意到我通过移动应用程序发送的是我的 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',
}
})