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

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

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:

  1. # models.py
  2. from django.db import models
  3. # Create your models here.
  4. class PDFFile(models.Model):
  5. name = models.CharField(max_length=200, blank=True)
  6. pdf_file = models.FileField(upload_to="pdfs/", blank=True)
  7. def __str__(self):
  8. return str(self.name)
  9. # serializers.py
  10. from rest_framework import serializers
  11. from .models import PDFFile
  12. class PDFFileModelSerializer(serializers.ModelSerializer):
  13. class Meta:
  14. model = PDFFile
  15. fields = ["id", "name", "pdf_file"]
  16. # views.py
  17. from .models import PDFFile
  18. from .serializers import PDFFileModelSerializer
  19. from rest_framework import viewsets, status
  20. from rest_framework.parsers import MultiPartParser, FormParser
  21. from rest_framework.response import Response
  22. class PDFFileViewSet(viewsets.ModelViewSet):
  23. queryset = PDFFile.objects.all()
  24. serializer_class = PDFFileModelSerializer
  25. parser_classes = (MultiPartParser, FormParser)
  26. def create(self, request, *args, **kwargs):
  27. name = request.data["name"]
  28. pdf_file = request.data["pdf_file"]
  29. print("PDF FILE: ", pdf_file)
  30. PDFFile.objects.create(name=name, pdf_file=pdf_file)
  31. return Response("PDF create with success!", status=status.HTTP_200_OK)
  32. # urls.py from the app
  33. from rest_framework import routers
  34. from .views import PDFFileViewSet
  35. from django.urls import path, include
  36. router = routers.DefaultRouter()
  37. router.register("pdfs", PDFFileViewSet)
  38. urlpatterns = [
  39. path("", include(router.urls))
  40. ]
  41. # urls.py from the project
  42. from django.contrib import admin
  43. from django.urls import path, include
  44. from django.conf import settings
  45. from django.conf.urls.static import static
  46. urlpatterns = [
  47. path('admin/', admin.site.urls),
  48. path('api/', include("pdf_uploader.urls")),
  49. ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  50. # settings.py
  51. REST_FRAMEWORK = {
  52. 'DEFAULT_PARSER_CLASSES': (
  53. 'rest_framework.parsers.FormParser',
  54. 'rest_framework.parsers.MultiPartParser'
  55. )
  56. }
  57. DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880
  58. STATIC_URL = '/static/'
  59. MEDIA_URL = '/media/'
  60. MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  61. STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
  62. 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.

  1. # models.py
  2. from django.db import models
  3. # Create your models here.
  4. class PDFFile(models.Model):
  5. name = models.CharField(max_length=200, blank=True)
  6. pdf_file = models.FileField(upload_to="pdfs/", blank=True)
  7. def __str__(self):
  8. return str(self.name)
  1. # serializers.py
  2. from rest_framework import serializers
  3. from .models import PDFFile
  4. class PDFFileModelSerializer(serializers.ModelSerializer):
  5. class Meta:
  6. model = PDFFile
  7. fields = ["id", "name", "pdf_file"]
  1. # views.py
  2. from .models import PDFFile
  3. from .serializers import PDFFileModelSerializer
  4. from rest_framework import viewsets, status
  5. from rest_framework.parsers import MultiPartParser, FormParser
  6. from rest_framework.response import Response
  7. class PDFFileViewSet(viewsets.ModelViewSet):
  8. queryset = PDFFile.objects.all()
  9. serializer_class = PDFFileModelSerializer
  10. parser_classes = (MultiPartParser, FormParser)
  11. def create(self, request, *args, **kwargs):
  12. name = request.data["name"]
  13. pdf_file = request.data["pdf_file"]
  14. print("PDF FILE: ", pdf_file)
  15. PDFFile.objects.create(name=name, pdf_file=pdf_file)
  16. return Response("PDF create with success!", status=status.HTTP_200_OK)
  1. # urls.py from the app
  2. from rest_framework import routers
  3. from .views import PDFFileViewSet
  4. from django.urls import path, include
  5. router = routers.DefaultRouter()
  6. router.register("pdfs", PDFFileViewSet)
  7. urlpatterns = [
  8. path("", include(router.urls))
  9. ]
  1. # urls.py from the project
  2. from django.contrib import admin
  3. from django.urls import path, include
  4. from django.conf import settings
  5. from django.conf.urls.static import static
  6. urlpatterns = [
  7. path('admin/', admin.site.urls),
  8. path('api/', include("pdf_uploader.urls")),
  9. ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  1. # settings.py
  2. REST_FRAMEWORK = {
  3. 'DEFAULT_PARSER_CLASSES': (
  4. 'rest_framework.parsers.FormParser',
  5. 'rest_framework.parsers.MultiPartParser'
  6. )
  7. }
  8. DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880
  9. STATIC_URL = '/static/'
  10. MEDIA_URL = '/media/'
  11. MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  12. STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
  13. STATIC_ROOT = BASE_DIR / 'staticfiles'

Expo React Native component:

  1. import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, Alert } from 'react-native'
  2. import React, { useState } from 'react'
  3. import * as DocumentPicker from 'expo-document-picker'
  4. import { PDF_BASE_URL } from '../data/api'
  5. const PdfPicker = () => {
  6. const [pdfFile, setPdfFile] = useState(null)
  7. const [name, setName] = useState("")
  8. const [uploading, setUploading] = useState(false)
  9. const pickerPdf = async () => {
  10. let result = await DocumentPicker.getDocumentAsync({
  11. type: 'application/pdf',
  12. })
  13. const fileName = result.uri.split('/').pop() // extract the file name from the URI
  14. const source = { uri: fileName, name: result.name }
  15. console.log("source", source)
  16. setPdfFile(source.uri)
  17. setName(source.name)
  18. }
  19. const uploadPdfFile = async () => {
  20. setUploading(true)
  21. const uploadPdf = pdfFile
  22. const pdfName = name
  23. const data = new FormData()
  24. data.append("name", pdfName)
  25. data.append("pdf_file", uploadPdf)
  26. const response = await fetch(PDF_BASE_URL + "pdfs/", {
  27. method: "POST",
  28. headers: {
  29. "Content-Type": "multipart/form-data",
  30. },
  31. body: data
  32. })
  33. console.log("RESULT: ", JSON.stringify(response))
  34. try {
  35. await JSON.stringify(response)
  36. } catch (e) {
  37. console.log("Catch error:", e)
  38. }
  39. setUploading(false)
  40. Alert.alert(
  41. "Pdf file uploaded..!!"
  42. )
  43. setName("")
  44. setPdfFile(null)
  45. }
  46. return (
  47. <SafeAreaView style={styles.container} >
  48. <View>
  49. <Text style={{color: "white", marginBottom: 30}}>{name}</Text>
  50. </View>
  51. <TouchableOpacity style={styles.selectButton} onPress={pickerPdf} >
  52. <Text style={styles.buttonText}>Pick a Pdf file</Text>
  53. </TouchableOpacity>
  54. <View style={styles.pdfContainer}>
  55. <TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}>
  56. <Text style={styles.buttonText}>Upload Pdf file</Text>
  57. </TouchableOpacity>
  58. </View>
  59. </SafeAreaView>
  60. )
  61. }
  62. export default PdfPicker
  63. const styles = StyleSheet.create({
  64. container: {
  65. flex: 1,
  66. alignItems: 'center',
  67. backgroundColor: '#000',
  68. justifyContent: 'center',
  69. },
  70. selectButton: {
  71. borderRadius: 5,
  72. width: 150,
  73. height: 50,
  74. backgroundColor: 'blue',
  75. alignItems: 'center',
  76. justifyContent: 'center',
  77. },
  78. buttonText: {
  79. color: 'white',
  80. fontSize: 18,
  81. fontWeight: 'bold'
  82. },
  83. pdfContainer: {
  84. marginTop: 30,
  85. marginBottom: 50,
  86. alignItems: 'center',
  87. },
  88. uploadButton: {
  89. borderRadius: 5,
  90. width: 150,
  91. height: 50,
  92. backgroundColor: 'green',
  93. alignItems: 'center',
  94. justifyContent: 'center',
  95. }
  96. })

The Expo log

  1. 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:

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

Sent by Expo app

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

Backend log:

  1. 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文件,所以我开始在移动应用上下载文件,然后发送到我的后端。

并且成功了。以下是代码:

  1. import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, Alert } from 'react-native'
  2. import React, { useState } from 'react'
  3. import * as DocumentPicker from 'expo-document-picker'
  4. import { PDF_BASE_URL } from '../data/api'
  5. import * as FileSystem from 'expo-file-system'
  6. const PdfTry = () => {
  7. const [pdfFileUri, setPdfFileUri] = useState(null)
  8. const [pdfFileName, setPdfFileName] = useState("")
  9. const [uploading, setUploading] = useState(false)
  10. const pickerPdf = async () => {
  11. let result = await DocumentPicker.getDocumentAsync({
  12. type: 'application/pdf',
  13. copyToCacheDirectory: false
  14. })
  15. const pdfUri = result.uri
  16. const pdfName = result.name
  17. // Download the selected PDF file to the device's local storage
  18. const fileUri = FileSystem.documentDirectory + pdfName
  19. await FileSystem.copyAsync({ from: pdfUri, to: fileUri })
  20. setPdfFileUri(fileUri)
  21. setPdfFileName(pdfName)
  22. }
  23. const uploadPdfFile = async () => {
  24. if (!pdfFileUri) {
  25. Alert.alert("请先选择PDF文件。")
  26. return
  27. }
  28. setUploading(true)
  29. const data = new FormData()
  30. data.append("name", pdfFileName)
  31. data.append("pdf_file", { uri: pdfFileUri, name: pdfFileName, type: 'application/pdf' })
  32. const response = await fetch(PDF_BASE_URL + "pdf_upload/", {
  33. method: "POST",
  34. headers: {
  35. "Content-Type": "multipart/form-data",
  36. },
  37. body: data
  38. })
  39. try {
  40. await JSON.stringify(response)
  41. } catch (e) {
  42. console.log("捕获错误:", e)
  43. }
  44. setUploading(false)
  45. Alert.alert(
  46. "PDF文件已上传..!!"
  47. )
  48. setPdfFileName("")
  49. setPdfFileUri(null)
  50. }
  51. return (
  52. <SafeAreaView style={styles.container}>
  53. <View>
  54. <Text style={{ color: "white", marginBottom: 30 }}>{pdfFileName}</Text>
  55. </View>
  56. <TouchableOpacity style={styles.selectButton} onPress={pickerPdf}>
  57. <Text style={styles.buttonText}>选择PDF文件</Text>
  58. </TouchableOpacity>
  59. <View style={styles.pdfContainer}>
  60. <TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}>
  61. <Text style={styles.buttonText}>上传PDF文件</Text>
  62. </TouchableOpacity>
  63. </View>
  64. </SafeAreaView>
  65. )
  66. }
  67. export default PdfTry
  68. const styles = StyleSheet.create({
  69. container: {
  70. flex: 1,
  71. alignItems: 'center',
  72. backgroundColor: '#000',
  73. justifyContent: 'center',
  74. },
  75. selectButton: {
  76. borderRadius: 5,
  77. width: 150,
  78. height: 50,
  79. backgroundColor: 'blue',
  80. alignItems: 'center',
  81. justifyContent: 'center',
  82. },
  83. buttonText: {
  84. color: 'white',
  85. fontSize: 18,
  86. fontWeight: 'bold'
  87. },
  88. pdfContainer: {
  89. marginTop: 30,
  90. marginBottom: 50,
  91. alignItems: 'center',
  92. },
  93. uploadButton: {
  94. borderRadius: 5,
  95. width: 150,
  96. height: 50,
  97. backgroundColor: 'green',
  98. alignItems: 'center',
  99. justifyContent: 'center',
  100. }
  101. })

希望这对有相似或相近问题的人有所帮助。

英文:

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 -->

  1. import { View, Text, StyleSheet, TouchableOpacity, SafeAreaView, Alert } from &#39;react-native&#39;
  2. import React, { useState } from &#39;react&#39;
  3. import * as DocumentPicker from &#39;expo-document-picker&#39;
  4. import { PDF_BASE_URL } from &#39;../data/api&#39;
  5. import * as FileSystem from &#39;expo-file-system&#39;;
  6. const PdfTry = () =&gt; {
  7. const [pdfFileUri, setPdfFileUri] = useState(null)
  8. const [pdfFileName, setPdfFileName] = useState(&quot;&quot;)
  9. const [uploading, setUploading] = useState(false)
  10. const pickerPdf = async () =&gt; {
  11. let result = await DocumentPicker.getDocumentAsync({
  12. type: &#39;application/pdf&#39;,
  13. copyToCacheDirectory: false
  14. })
  15. const pdfUri = result.uri
  16. const pdfName = result.name
  17. // Download the selected PDF file to the device&#39;s local storage
  18. const fileUri = FileSystem.documentDirectory + pdfName
  19. await FileSystem.copyAsync({ from: pdfUri, to: fileUri })
  20. setPdfFileUri(fileUri)
  21. setPdfFileName(pdfName)
  22. }
  23. const uploadPdfFile = async () =&gt; {
  24. if (!pdfFileUri) {
  25. Alert.alert(&quot;Please select a PDF file first.&quot;)
  26. return
  27. }
  28. setUploading(true)
  29. const data = new FormData()
  30. data.append(&quot;name&quot;, pdfFileName)
  31. data.append(&quot;pdf_file&quot;, { uri: pdfFileUri, name: pdfFileName, type: &#39;application/pdf&#39; })
  32. const response = await fetch(PDF_BASE_URL + &quot;pdf_upload/&quot;, {
  33. method: &quot;POST&quot;,
  34. headers: {
  35. &quot;Content-Type&quot;: &quot;multipart/form-data&quot;,
  36. },
  37. body: data
  38. })
  39. try {
  40. await JSON.stringify(response)
  41. } catch (e) {
  42. console.log(&quot;Catch error:&quot;, e)
  43. }
  44. setUploading(false)
  45. Alert.alert(
  46. &quot;Pdf file uploaded..!!&quot;
  47. )
  48. setPdfFileName(&quot;&quot;)
  49. setPdfFileUri(null)
  50. }
  51. return (
  52. &lt;SafeAreaView style={styles.container} &gt;
  53. &lt;View&gt;
  54. &lt;Text style={{color: &quot;white&quot;, marginBottom: 30}}&gt;{pdfFileName}&lt;/Text&gt;
  55. &lt;/View&gt;
  56. &lt;TouchableOpacity style={styles.selectButton} onPress={pickerPdf} &gt;
  57. &lt;Text style={styles.buttonText}&gt;Pick a Pdf file&lt;/Text&gt;
  58. &lt;/TouchableOpacity&gt;
  59. &lt;View style={styles.pdfContainer}&gt;
  60. &lt;TouchableOpacity style={styles.uploadButton} onPress={uploadPdfFile}&gt;
  61. &lt;Text style={styles.buttonText}&gt;Upload Pdf file&lt;/Text&gt;
  62. &lt;/TouchableOpacity&gt;
  63. &lt;/View&gt;
  64. &lt;/SafeAreaView&gt;
  65. )
  66. }
  67. export default PdfTry
  68. const styles = StyleSheet.create({
  69. container: {
  70. flex: 1,
  71. alignItems: &#39;center&#39;,
  72. backgroundColor: &#39;#000&#39;,
  73. justifyContent: &#39;center&#39;,
  74. },
  75. selectButton: {
  76. borderRadius: 5,
  77. width: 150,
  78. height: 50,
  79. backgroundColor: &#39;blue&#39;,
  80. alignItems: &#39;center&#39;,
  81. justifyContent: &#39;center&#39;,
  82. },
  83. buttonText: {
  84. color: &#39;white&#39;,
  85. fontSize: 18,
  86. fontWeight: &#39;bold&#39;
  87. },
  88. pdfContainer: {
  89. marginTop: 30,
  90. marginBottom: 50,
  91. alignItems: &#39;center&#39;,
  92. },
  93. uploadButton: {
  94. borderRadius: 5,
  95. width: 150,
  96. height: 50,
  97. backgroundColor: &#39;green&#39;,
  98. alignItems: &#39;center&#39;,
  99. justifyContent: &#39;center&#39;,
  100. }
  101. })

<!-- 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:

确定