英文:
Expo React Native post method not including MEDIA on Django rest framework right path
问题
I'm here to assist with the translation. Here is the translated code part:
# 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'
Please note that the translation doesn't include the Expo React Native component code. If you need any further assistance or have specific questions about the code, feel free to ask.
英文:
I'm trying to create an Expo React Native app where I send a Pdf File to my API created in Django Rest Framework.
But, when I send the pdf file, it is not being save on the right place, I'll put the code and logs to explain better.
# 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 component:
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',
}
})
The Expo log
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":{}}}}
Sent by the browser:
{
"id": 5,
"name": "livro",
"pdf_file": "{my.server}/media/pdfs/Stephen.King.-.A.Balsa_WF9W8Kc.pdf"
}
Sent by Expo app
{
"id": 4,
"name": "CERTIDAO-IANDERSONPIZETTEUENDERSONPABLOIII.pdf",
"pdf_file": "{my.server}/media/C2699748-A1CF-49F5-A3C7-6B527AD3FF44.pdf"
},
Backend log:
Not Found: /media/C2699748-A1CF-49F5-A3C7-6B527AD3FF44.pdf
So, I can't see where is my problem here.
Maybe a new pair of eyes can help me.
I had read Django and DRF documentation, Expo React Native documentation.
I tried get help from ChatGPT.
Now I'm trying get some help here.
答案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("请先选择PDF文件。")
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("捕获错误:", e)
}
setUploading(false)
Alert.alert(
"PDF文件已上传..!!"
)
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}>选择PDF文件</Text>
</TouchableOpacity>
<View style={styles.pdfContainer}>
<TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}>
<Text style={styles.buttonText}>上传PDF文件</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',
}
})
希望这对有相似或相近问题的人有所帮助。
英文:
I got the solution for my problem, I notice that what I was sending was the blobId of my pdf file by the mobile app, and by the browser,I was sending the downloaded pdf file, so I start to download the file on mobile app and then send to my backend.
and worked. Here the code. I'll share the my solution for those who come on this post with same or close problem like mine.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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',
}
})
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论