Expo React Native的POST方法在Django REST框架的正确路径上不包括媒体。

huangapple go评论57阅读模式
英文:

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 &#39;react-native&#39;
import React, { useState } from &#39;react&#39;
import * as DocumentPicker from &#39;expo-document-picker&#39;
import { PDF_BASE_URL } from &#39;../data/api&#39;
import * as FileSystem from &#39;expo-file-system&#39;;
const PdfTry = () =&gt; {
const [pdfFileUri, setPdfFileUri] = useState(null)
const [pdfFileName, setPdfFileName] = useState(&quot;&quot;)
const [uploading, setUploading] = useState(false)
const pickerPdf = async () =&gt; {
let result = await DocumentPicker.getDocumentAsync({
type: &#39;application/pdf&#39;,
copyToCacheDirectory: false
})
const pdfUri = result.uri
const pdfName = result.name
// Download the selected PDF file to the device&#39;s local storage
const fileUri = FileSystem.documentDirectory + pdfName
await FileSystem.copyAsync({ from: pdfUri, to: fileUri })
setPdfFileUri(fileUri)
setPdfFileName(pdfName)
}
const uploadPdfFile = async () =&gt; {
if (!pdfFileUri) {
Alert.alert(&quot;Please select a PDF file first.&quot;)
return
}
setUploading(true)
const data = new FormData()
data.append(&quot;name&quot;, pdfFileName)
data.append(&quot;pdf_file&quot;, { uri: pdfFileUri, name: pdfFileName, type: &#39;application/pdf&#39; })
const response = await fetch(PDF_BASE_URL + &quot;pdf_upload/&quot;, {
method: &quot;POST&quot;,
headers: {
&quot;Content-Type&quot;: &quot;multipart/form-data&quot;,
},
body: data
})
try {
await JSON.stringify(response)
} catch (e) {
console.log(&quot;Catch error:&quot;, e)
}
setUploading(false)
Alert.alert(
&quot;Pdf file uploaded..!!&quot;
)
setPdfFileName(&quot;&quot;)
setPdfFileUri(null)
}
return (
&lt;SafeAreaView style={styles.container} &gt;
&lt;View&gt;
&lt;Text style={{color: &quot;white&quot;, marginBottom: 30}}&gt;{pdfFileName}&lt;/Text&gt;
&lt;/View&gt;
&lt;TouchableOpacity style={styles.selectButton} onPress={pickerPdf} &gt;
&lt;Text style={styles.buttonText}&gt;Pick a Pdf file&lt;/Text&gt;
&lt;/TouchableOpacity&gt;
&lt;View style={styles.pdfContainer}&gt;
&lt;TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}&gt;
&lt;Text style={styles.buttonText}&gt;Upload Pdf file&lt;/Text&gt;
&lt;/TouchableOpacity&gt;
&lt;/View&gt;
&lt;/SafeAreaView&gt;
)
}
export default PdfTry
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: &#39;center&#39;,
backgroundColor: &#39;#000&#39;,
justifyContent: &#39;center&#39;,
},
selectButton: {
borderRadius: 5,
width: 150,
height: 50,
backgroundColor: &#39;blue&#39;,
alignItems: &#39;center&#39;,
justifyContent: &#39;center&#39;,
},
buttonText: {
color: &#39;white&#39;,
fontSize: 18,
fontWeight: &#39;bold&#39;
},
pdfContainer: {
marginTop: 30,
marginBottom: 50,
alignItems: &#39;center&#39;,
},
uploadButton: {
borderRadius: 5,
width: 150,
height: 50,
backgroundColor: &#39;green&#39;,
alignItems: &#39;center&#39;,
justifyContent: &#39;center&#39;,
}
})

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年4月6日 22:28:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75950693.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定