Django रेस्ट फ्रेमवर्क फाइल अपलोड


98

मैं एक फ़ाइल अपलोड करने के लिए Django रेस्ट फ्रेमवर्क और AngularJs का उपयोग कर रहा हूं। मेरा दृश्य फ़ाइल इस तरह दिखता है:

class ProductList(APIView):
    authentication_classes = (authentication.TokenAuthentication,)
    def get(self,request):
        if request.user.is_authenticated(): 
            userCompanyId = request.user.get_profile().companyId
            products = Product.objects.filter(company = userCompanyId)
            serializer = ProductSerializer(products,many=True)
            return Response(serializer.data)

    def post(self,request):
        serializer = ProductSerializer(data=request.DATA, files=request.FILES)
        if serializer.is_valid():
            serializer.save()
            return Response(data=request.DATA)

पोस्ट विधि की अंतिम पंक्ति के रूप में सभी डेटा वापस आ जाना चाहिए, मेरे पास कई प्रश्न हैं:

  • अगर कुछ है तो कैसे जांचें request.FILES?
  • फ़ाइल फ़ील्ड को क्रमबद्ध कैसे करें?
  • मुझे पार्सर का उपयोग कैसे करना चाहिए?

8
मोड पर ध्यान दें: Django ने 2013 के बाद से बहुत उन्नयन किया है। इसलिए यदि कोई व्यक्ति अब उसी प्रश्न को पोस्ट करता है। कृपया उन्हें नीचे ^ ^ ^ गोली न दें।
जेसी

बेस 64 के बारे में कैसे?
होजत मोदारेसी

जवाबों:


67

FileUploadParser का उपयोग करें , यह सभी अनुरोध में है। इसके बजाय एक पुट विधि का उपयोग करें, आपको डॉक्स में एक उदाहरण मिलेगा :)

class FileUploadView(views.APIView):
    parser_classes = (FileUploadParser,)

    def put(self, request, filename, format=None):
        file_obj = request.FILES['file']
        # do some stuff with uploaded file
        return Response(status=204)

12
@pleasedontbelong क्यों POST के बजाय यहाँ PUT पद्धति का उपयोग किया गया है?
एमडी। तनवीर रायहान

8
hi @pleasedontbelong, यदि यह एक नया रिकॉर्ड बना रहा है, तो क्या इसकी जगह POST होगा? और क्या यह अभी भी FileUploadParser के साथ काम करेगा?
न्यूटनिबल्स 2

1
@pleasedontbelong RTan एक बहुत अच्छा सवाल पूछता है। RFC-2616 पढ़ना एक सूक्ष्मता प्रदान करता है जो मुझे अब तक पता नहीं था। "POST और PUT अनुरोधों के बीच मूलभूत अंतर अनुरोध-URI के अलग-अलग अर्थों में परिलक्षित होता है। POST अनुरोध में URI उस संसाधन की पहचान करता है जो संलग्न इकाई को संभालेगा। यह संसाधन डेटा-स्वीकार करने की प्रक्रिया, एक प्रवेश द्वार हो सकता है। कुछ अन्य प्रोटोकॉल, या एक अलग इकाई जो एनोटेशन को स्वीकार करती है। इसके विपरीत, PUT अनुरोध में URI अनुरोध के साथ संलग्न इकाई की पहचान करता है "
dudeman

2
FileUploadParser क्यों? "FileUploadParser मूल ग्राहकों के साथ उपयोग के लिए है जो फ़ाइल को कच्चे डेटा अनुरोध के रूप में अपलोड कर सकते हैं। वेब-आधारित अपलोड के लिए, या मल्टीपार्ट अपलोड समर्थन वाले मूल ग्राहकों के लिए, आपको इसके बजाय MultiPartParser पार्सर का उपयोग करना चाहिए।" आम तौर पर एक अच्छा विकल्प नहीं लगता है। क्या अधिक है, मुझे किसी विशेष उपचार की आवश्यकता वाले फ़ाइल अपलोड नहीं दिख रहे हैं ।
x- यूरी

3
दूसरे @ x-yuri से, जब मैं FileUploadPserser का उपयोग करता हूं तो DRF कंटेंट-डिस्पोजल हेडर खाली होने की शिकायत करता है। MultiPartParser बहुत सरल है, क्योंकि यह सिर्फ फॉर्म फ़ील्ड में दिए गए फ़ाइल नाम होने के लिए फ़ाइलनाम को मानता है।
डेविड ज़्वार्ट

74

मैं उसी स्टैक का उपयोग कर रहा हूं और फ़ाइल अपलोड के उदाहरण की भी तलाश कर रहा था, लेकिन जब से मैं APIView के बजाय ModelViewSet का उपयोग करता हूं, तो मेरा मामला सरल है। यह कुंजी प्री_सैव हुक है। मैंने इसे कोणीय-फ़ाइल-अपलोड मॉड्यूल के साथ एक साथ उपयोग करना समाप्त कर दिया जैसे:

# Django
class ExperimentViewSet(ModelViewSet):
    queryset = Experiment.objects.all()
    serializer_class = ExperimentSerializer

    def pre_save(self, obj):
        obj.samplesheet = self.request.FILES.get('file')

class Experiment(Model):
    notes = TextField(blank=True)
    samplesheet = FileField(blank=True, default='')
    user = ForeignKey(User, related_name='experiments')

class ExperimentSerializer(ModelSerializer):
    class Meta:
        model = Experiment
        fields = ('id', 'notes', 'samplesheet', 'user')

// AngularJS
controller('UploadExperimentCtrl', function($scope, $upload) {
    $scope.submit = function(files, exp) {
        $upload.upload({
            url: '/api/experiments/' + exp.id + '/',
            method: 'PUT',
            data: {user: exp.user.id},
            file: files[0]
        });
    };
});

11
pre_save को df 3.x
Guy S

मेरे अनुभव से, फ़ाइल फ़ील्ड के लिए किसी विशेष उपचार की आवश्यकता नहीं है ।
x- यूरी

@ गाइ-एस, Perform_create, perform_update, perform_destroy तरीके पुराने शैली के संस्करण 2.x pre_save, post_save, pre_delete और post_delete तरीके बदलते हैं, जो अब उपलब्ध नहीं हैं: django-rest-framework.org/api-guide/generic-views / # विधियाँ
रफत

37

अंत में मैं Django का उपयोग करके छवि अपलोड करने में सक्षम हूं। यहाँ मेरा काम कोड है

views.py

class FileUploadView(APIView):
    parser_classes = (FileUploadParser, )

    def post(self, request, format='jpg'):
        up_file = request.FILES['file']
        destination = open('/Users/Username/' + up_file.name, 'wb+')
        for chunk in up_file.chunks():
            destination.write(chunk)
        destination.close()  # File should be closed only after all chuns are added

        # ...
        # do some stuff with uploaded file
        # ...
        return Response(up_file.name, status.HTTP_201_CREATED)

urls.py

urlpatterns = patterns('', 
url(r'^imageUpload', views.FileUploadView.as_view())

अपलोड करने का अनुरोध

curl -X POST -S -H -u "admin:password" -F "file=@img.jpg;type=image/jpg" 127.0.0.1:8000/resourceurl/imageUpload

14
क्यों गंतव्य। क्लोज () को लूप के अंदर रखा जाता है?
मेकरज

12
लगता है कि इसका उपयोग करना with open('/Users/Username/' + up_file.name, 'wb+') as destination:और पूरी तरह से बंद करना बेहतर होगा
चक विल्बर

यह उपयोग करने के लिए सरल है ModelViewSet। साथ ही, उन्होंने सबसे बेहतर तरीके से इसे लागू किया।
x- यूरी

मैं पूरे दिन के लिए इस उत्तरदाता पर भरोसा कर रहा हूं ... जब तक मैंने यह नहीं पाया कि जब आप कई फाइलें अपलोड करना चाहते हैं, तो FileUploadParserइसकी जरूरत नहीं है, लेकिन MultiPartParser!
ओलिवियर पोंस

13

इस पर 1 दिन बिताने के बाद, मुझे लगा कि ...

किसी ऐसे व्यक्ति के लिए जिसे किसी फ़ाइल को अपलोड करने और कुछ डेटा भेजने की आवश्यकता है, कोई सीधा fwd तरीका नहीं है जो आप इसे काम करने के लिए प्राप्त कर सकते हैं। इसके लिए json api स्पेक्स में एक खुला मुद्दा है। एक संभावना जिसे मैंने देखा है , multipart/relatedजैसा कि यहाँ दिखाया गया है , लेकिन मुझे लगता है कि इसे ड्रॉ में लागू करना बहुत कठिन है।

अंत में मैंने जो लागू किया था वह अनुरोध भेजना था formdata। आप के रूप में प्रत्येक फ़ाइल भेजना होगा फ़ाइल और पाठ के रूप में अन्य सभी डेटा। अब पाठ के रूप में डेटा भेजने के लिए आपके पास दो विकल्प हैं। केस 1) आप प्रत्येक डेटा को मुख्य मूल्य जोड़ी या केस 2 के रूप में भेज सकते हैं) आपके पास एक एकल कुंजी हो सकती है जिसे डेटा कहा जाता है और पूरे json को स्ट्रिंग के रूप में मूल्य में भेज सकता है।

यदि आपके पास सरल फ़ील्ड हैं, तो पहली विधि बॉक्स से बाहर निकलेगी, लेकिन यदि आपके पास नेस्टेड अनुक्रमित हैं तो यह एक समस्या होगी। मल्टीपार्ट पार्सर अभ्यस्त नेस्टेड फ़ील्ड को पार्स करने में सक्षम है।

नीचे मैं दोनों मामलों के लिए कार्यान्वयन प्रदान कर रहा हूं

Models.py

class Posts(models.Model):
    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
    caption = models.TextField(max_length=1000)
    media = models.ImageField(blank=True, default="", upload_to="posts/")
    tags = models.ManyToManyField('Tags', related_name='posts')

serializers.py -> कोई विशेष परिवर्तन की आवश्यकता नहीं है, मेरे क्रम को यहां दिखाने योग्य नहीं है क्योंकि कई माननीय फ़ील्ड के अव्यवस्था के कारण यह बहुत लंबा है।

views.py

class PostsViewset(viewsets.ModelViewSet):
    serializer_class = PostsSerializer
    #parser_classes = (MultipartJsonParser, parsers.JSONParser) use this if you have simple key value pair as data with no nested serializers
    #parser_classes = (parsers.MultipartParser, parsers.JSONParser) use this if you want to parse json in the key value pair data sent
    queryset = Posts.objects.all()
    lookup_field = 'id'

अब, यदि आप पहली विधि का पालन कर रहे हैं और केवल गैर-जोंस डेटा को मुख्य मूल्य जोड़े के रूप में भेज रहे हैं, तो आपको एक कस्टम पार्सर वर्ग की आवश्यकता नहीं है। DRF'd MultipartParser काम करेगा। लेकिन दूसरे मामले के लिए या यदि आपके पास नेस्टाइज़र हैं (जैसे मैंने दिखाया है) तो आपको कस्टम पार्सर की आवश्यकता होगी जैसा कि नीचे दिखाया गया है।

utils.py

from django.http import QueryDict
import json
from rest_framework import parsers

class MultipartJsonParser(parsers.MultiPartParser):

    def parse(self, stream, media_type=None, parser_context=None):
        result = super().parse(
            stream,
            media_type=media_type,
            parser_context=parser_context
        )
        data = {}

        # for case1 with nested serializers
        # parse each field with json
        for key, value in result.data.items():
            if type(value) != str:
                data[key] = value
                continue
            if '{' in value or "[" in value:
                try:
                    data[key] = json.loads(value)
                except ValueError:
                    data[key] = value
            else:
                data[key] = value

        # for case 2
        # find the data field and parse it
        data = json.loads(result.data["data"])

        qdict = QueryDict('', mutable=True)
        qdict.update(data)
        return parsers.DataAndFiles(qdict, result.files)

यह धारावाहिक मूल रूप से मूल्यों में किसी भी json सामग्री को पार्स करेगा।

दोनों मामलों के लिए पोस्ट मैन में अनुरोध उदाहरण: केस 1 मामला एक,

केस 2 case2


मैं मामले से बचना चाहता हूं। 2. प्रति अनुरोध एक डेटाबेस रिकॉर्ड बनाना अधिकांश समय ठीक होना चाहिए।
x- यूरी

बहुत मददगार आपको बहुत-बहुत धन्यवाद। लेकिन मुझे समझ में नहीं आ रहा है, कि आप पैरासेर में डिक्लेयर डेटा को क्यूरीडक्ट में क्यों बदल रहे हैं? Django में मेरे मामले में, सामान्य शब्दकोश डेटा पूरी तरह से परिवर्तित किए बिना काम करते हैं।
मेटेहन गुलाक

मैंने आपके द्वारा बताए गए उत्तर का उपयोग करके एक अलग परिदृश्य की कोशिश की और यह सफलतापूर्वक काम करता है। आप मेरे उत्तर को देख सकते हैं ।
मेटेहन गुलाक

7

मैंने ModelViewSet और ModelSerializer के साथ इस समस्या को हल किया। उम्मीद है कि इससे समुदाय को मदद मिलेगी।

मैं सत्यापन और उद्देश्य-> JSON (और इसके विपरीत) को देखने के बजाय धारावाहिक में लॉगिन करने का प्रस्ताव रखता हूं।

इसे उदाहरण से समझते हैं।

कहो, मैं FileUploader API बनाना चाहता हूं। जहाँ यह डेटाबेस में id, file_path, file_name, size, owner आदि जैसे फ़ील्ड्स को स्टोर करेगा। नीचे नमूना मॉडल देखें:

class FileUploader(models.Model):
    file = models.FileField()
    name = models.CharField(max_length=100) #name is filename without extension
    version = models.IntegerField(default=0)
    upload_date = models.DateTimeField(auto_now=True, db_index=True)
    owner = models.ForeignKey('auth.User', related_name='uploaded_files')
    size = models.IntegerField(default=0)

अब, एपीआई के लिए यह वही है जो मैं चाहता हूं:

  1. प्राप्त:

जब मैं GET समापन बिंदु पर आग लगाता हूं, तो मुझे हर अपलोड की गई फ़ाइल के लिए सभी फ़ील्ड ऊपर चाहिए।

  1. पद:

लेकिन उपयोगकर्ता को फ़ाइल बनाने / अपलोड करने के लिए, उसे इन सभी क्षेत्रों को पारित करने की चिंता क्यों करनी होगी। वह सिर्फ फाइल अपलोड कर सकती है और फिर, मुझे लगता है, सीरियललाइजर को अपलोड किए गए FILE से बाकी क्षेत्र मिल सकते हैं।

Searilizer: प्रश्न: मैं अपने उद्देश्य की सेवा करने के लिए serializer के नीचे बनाया गया। लेकिन यकीन नहीं है कि अगर इसे लागू करने का सही तरीका है।

class FileUploaderSerializer(serializers.ModelSerializer):
    # overwrite = serializers.BooleanField()
    class Meta:
        model = FileUploader
        fields = ('file','name','version','upload_date', 'size')
        read_only_fields = ('name','version','owner','upload_date', 'size')

   def validate(self, validated_data):
        validated_data['owner'] = self.context['request'].user
        validated_data['name'] = os.path.splitext(validated_data['file'].name)[0]
        validated_data['size'] = validated_data['file'].size
        #other validation logic
        return validated_data

    def create(self, validated_data):
        return FileUploader.objects.create(**validated_data)

संदर्भ के लिए दृश्य:

class FileUploaderViewSet(viewsets.ModelViewSet):
    serializer_class = FileUploaderSerializer
    parser_classes = (MultiPartParser, FormParser,)

    # overriding default query set
    queryset = LayerFile.objects.all()

    def get_queryset(self, *args, **kwargs):
        qs = super(FileUploaderViewSet, self).get_queryset(*args, **kwargs)
        qs = qs.filter(owner=self.request.user)
        return qs

FileUploaderSerializer.validateविधि में क्या तर्क तर्क है ?
x- यूरी

7

मेरे अनुभव से, आपको फ़ाइल फ़ील्ड के बारे में कुछ विशेष करने की आवश्यकता नहीं है, आप इसे फ़ाइल फ़ील्ड का उपयोग करने के लिए कहेंगे:

from rest_framework import routers, serializers, viewsets

class Photo(django.db.models.Model):
    file = django.db.models.ImageField()

    def __str__(self):
        return self.file.name

class PhotoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Photo
        fields = ('id', 'file')   # <-- HERE

class PhotoViewSet(viewsets.ModelViewSet):
    queryset = models.Photo.objects.all()
    serializer_class = PhotoSerializer

router = routers.DefaultRouter()
router.register(r'photos', PhotoViewSet)

api_urlpatterns = ([
    url('', include(router.urls)),
], 'api')
urlpatterns += [
    url(r'^api/', include(api_urlpatterns)),
]

और आप फाइलें अपलोड करने के लिए तैयार हैं:

curl -sS http://example.com/api/photos/ -F 'file=@/path/to/file'

-F field=valueआपके मॉडल में प्रत्येक अतिरिक्त फ़ील्ड के लिए जोड़ें । और प्रमाणीकरण जोड़ने के लिए मत भूलना।


4

अगर किसी को Django रेस्ट फ्रेमवर्क के लिए ModelViewset के साथ सबसे आसान उदाहरण में दिलचस्पी है।

मॉडल है,

class MyModel(models.Model):
    name = models.CharField(db_column='name', max_length=200, blank=False, null=False, unique=True)
    imageUrl = models.FileField(db_column='image_url', blank=True, null=True, upload_to='images/')

    class Meta:
        managed = True
        db_table = 'MyModel'

धारावाहिक,

class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = "__all__"

और देखें,

class MyModelView(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

पोस्टमैन में टेस्ट,

यहां छवि विवरण दर्ज करें


और हम अजाक्स का उपयोग करके अनुरोध कैसे भेज सकते हैं। ImageUrl वास्तव में क्या है?
एडुआर्ड ग्रिगोरीव

छवि अनुरोध में फ़ाइल है।
सआदत

0

Django- रेस्ट-फ्रेमवर्क अनुरोध में डेटा पार्स किया गया है Parsers
http://www.django-rest-framework.org/api-guide/parsers/

डिफ़ॉल्ट रूप से django-rest- फ्रेमवर्क पार्सर क्लास लेता है JSONParser। यह डेटा को json में पार्स कर देगा। इसलिए, फ़ाइलों को इसके साथ पार्स नहीं किया जाएगा।
यदि हम चाहते हैं कि फ़ाइलों को अन्य डेटा के साथ पार्स किया जाए तो हमें नीचे दिए गए पार्सर वर्गों में से एक का उपयोग करना चाहिए।

FormParser
MultiPartParser
FileUploadParser

डीआरएफ 3.8.2 के वर्तमान संस्करण पर, यह डिफ़ॉल्ट रूप से पार्स होगा application/json, application/x-www-form-urlencoded, और multipart/form-data
लिक्की

0
    from rest_framework import status
    from rest_framework.response import Response
    class FileUpload(APIView):
         def put(request):
             try:
                file = request.FILES['filename']
                #now upload to s3 bucket or your media file
             except Exception as e:
                   print e
                   return Response(status, 
                           status.HTTP_500_INTERNAL_SERVER_ERROR)
             return Response(status, status.HTTP_200_OK)


0

मैं एक और विकल्प लिखना चाहता हूं जो मुझे लगता है कि क्लीनर और बनाए रखने में आसान है। हम अपने व्यूसेट के लिए CRUD urls जोड़ने के लिए defaultRouter का उपयोग करेंगे और हम अपलोडर व्यू को एक ही व्यूसेट में निर्दिष्ट करते हुए एक और निश्चित url जोड़ेंगे।

**** views.py 

from rest_framework import viewsets, serializers
from rest_framework.decorators import action, parser_classes
from rest_framework.parsers import JSONParser, MultiPartParser
from rest_framework.response import Response
from rest_framework_csv.parsers import CSVParser
from posts.models import Post
from posts.serializers import PostSerializer     


class PostsViewSet(viewsets.ModelViewSet):

    queryset = Post.objects.all()
    serializer_class = PostSerializer 
    parser_classes = (JSONParser, MultiPartParser, CSVParser)


    @action(detail=False, methods=['put'], name='Uploader View', parser_classes=[CSVParser],)
    def uploader(self, request, filename, format=None):
        # Parsed data will be returned within the request object by accessing 'data' attr  
        _data = request.data

        return Response(status=204)

प्रोजेक्ट का मुख्य urls.py

**** urls.py 

from rest_framework import routers
from posts.views import PostsViewSet


router = routers.DefaultRouter()
router.register(r'posts', PostsViewSet)

urlpatterns = [
    url(r'^posts/uploader/(?P<filename>[^/]+)$', PostsViewSet.as_view({'put': 'uploader'}), name='posts_uploader')
    url(r'^', include(router.urls), name='root-api'),
    url('admin/', admin.site.urls),
]

.- README

जादू तब होता है जब हम @ क्लास डेकोरेटर को हमारी क्लास मेथड 'अपलोडर' से जोड़ते हैं। "विधियों = ['डाल']" तर्क को निर्दिष्ट करके, हम केवल PUT अनुरोधों की अनुमति दे रहे हैं; फ़ाइल अपलोड करने के लिए एकदम सही है।

मैंने "parser_classes" तर्क भी जोड़ा, यह दिखाने के लिए कि आप उस पार्सर का चयन कर सकते हैं जो आपकी सामग्री को पार्स करेगा। मैंने CS_Parser को rest_framework_csv पैकेज से जोड़ा, यह प्रदर्शित करने के लिए कि हम केवल कुछ प्रकार की फ़ाइलों को कैसे स्वीकार कर सकते हैं यदि इस कार्यक्षमता की आवश्यकता है, मेरे मामले में मैं केवल "सामग्री-प्रकार: पाठ / सीएसवी" स्वीकार कर रहा हूं। नोट: यदि आप कस्टम पार्सर जोड़ रहे हैं, तो आपको उन्हें व्यूसेट में parsers_classes में निर्दिष्ट करना होगा क्योंकि अनुरोध अपलोडर विधि पार्सरों तक पहुँचने से पहले मुख्य (वर्ग) पार्सर्स के साथ अनुमत मीडिया_टाइप की तुलना करेगा।

अब हमें Django को यह बताने की आवश्यकता है कि इस पद्धति पर कैसे जाएं और हमारे urls में कहां लागू किया जा सकता है। जब हम निश्चित url (सरल उद्देश्य) जोड़ते हैं। यह अर्ल एक "फ़ाइलनाम" तर्क लेगा जिसे बाद में विधि में पारित किया जाएगा। हमें PostViewSet.as_view पद्धति की सूची में http प्रोटोकॉल ('PUT') को निर्दिष्ट करते हुए, इस विधि "अपलोडर" को पारित करने की आवश्यकता है।

जब हम निम्नलिखित यूआरएल में उतरते हैं

 http://example.com/posts/uploader/ 

यह "सामग्री-प्रकार" और सामग्री-विवाद: निर्दिष्ट करने वाले शीर्ष लेखों के साथ एक PUT अनुरोध की उम्मीद करेगा; फ़ाइल नाम = "something.csv"।

curl -v -u user:pass http://example.com/posts/uploader/ --upload-file ./something.csv --header "Content-type:text/csv"

तो आप एक फ़ाइल अपलोड करने का सुझाव देते हैं, फिर इसे कुछ डीबी रिकॉर्ड में संलग्न करते हैं। क्या होगा अगर अटैचमेंट कभी किसी कारण से न हो? एक अनुरोध में ऐसा क्यों नहीं करते? parser_classesयह सीमित करने के लिए नहीं है कि कौन सी फाइलें अपलोड की जा सकती हैं। आइए आपको बताते हैं कि अनुरोध करने के लिए किन स्वरूपों का उपयोग किया जा सकता है। दूसरे विचार पर, जिस तरह से आप अपलोड को हैंडल करते हैं ... ऐसा लगता है जैसे आप डेटाबेस में सीएसवी से डेटा डाल रहे हैं। ओपी ने जो नहीं पूछा।
x- यूरी

@ x- यूरी ने "एक सीएसवी एक फ़ाइल है" कहकर और सवाल किया; यदि अनुरोध में डेटा है तो कैसे जांचें? इस पद्धति का उपयोग करके, आपको request.data में डेटा मिलेगा। _data = request.data कारण PUT का उपयोग किया जा रहा है। जैसा कि आपने कहा, parser_classes यह तय करने के लिए हैं कि किन स्वरूपों का उपयोग करने के लिए अनुरोध किया जा सकता है इसलिए किसी भी अन्य प्रारूप का उपयोग करके जिसे आप नहीं चाहते हैं, तब सुरक्षा की एक अतिरिक्त परत को जोड़ने से बाहर रखा जाएगा। आप अपने डेटा के साथ क्या करते हैं, आप पर निर्भर है। "आज़माइश को छोड़कर" का उपयोग करके आप देख सकते हैं कि "अटैचमेंट कभी नहीं होता है" इसके लिए कोई आवश्यकता नहीं है, यह वह नहीं है जो कोड करता है। ये 1 अनुरोध में बनाया गया है
वोल्फगैंग लियोन

0

यह एक दृष्टिकोण है जिसे मैंने उम्मीद किया है कि यह मदद करेगा।

     class Model_File_update(APIView):
         parser_classes = (MultiPartParser, FormParser)
         permission_classes = [IsAuthenticated]  # it will check if the user is authenticated or not
         authentication_classes = [JSONWebTokenAuthentication]  # it will authenticate the person by JSON web token

         def put(self, request):
            id = request.GET.get('id')
            obj = Model.objects.get(id=id)
            serializer = Model_Upload_Serializer(obj, data=request.data)
            if serializer.is_valid():
               serializer.save()
               return Response(serializer.data, status=200)
            else:
               return Response(serializer.errors, status=400)

0

आप डीआरएफ की मौजूदा धारावाहिक प्रणाली के साथ सीधे काम करने के लिए @ नितिन के जवाब को सामान्य कर सकते हैं ताकि विशिष्ट क्षेत्रों को पार्स करने के लिए एक पार्सर वर्ग उत्पन्न करके जो सीधे मानक डीआरएफ धारावाहिकों में खिलाया जाता है:

from django.http import QueryDict
import json
from rest_framework import parsers


def gen_MultipartJsonParser(json_fields):
    class MultipartJsonParser(parsers.MultiPartParser):

        def parse(self, stream, media_type=None, parser_context=None):
            result = super().parse(
                stream,
                media_type=media_type,
                parser_context=parser_context
            )
            data = {}
            # find the data field and parse it
            qdict = QueryDict('', mutable=True)
            for json_field in json_fields:
                json_data = result.data.get(json_field, None)
                if not json_data:
                    continue
                data = json.loads(json_data)
                if type(data) == list:
                    for d in data:
                        qdict.update({json_field: d})
                else:
                    qdict.update({json_field: data})

            return parsers.DataAndFiles(qdict, result.files)

    return MultipartJsonParser

इसका उपयोग इस तरह किया जाता है:

class MyFileViewSet(ModelViewSet):
    parser_classes = [gen_MultipartJsonParser(['tags', 'permissions'])]
    #                                           ^^^^^^^^^^^^^^^^^^^
    #                              Fields that need to be further JSON parsed
    ....

0

यदि आप ModelViewSet का उपयोग कर रहे हैं, तो वास्तव में आप कर रहे हैं! यह आपके लिए हर चीज़ को संभालता है! आपको बस अपने ModelSerializer में फ़ील्ड डालने और content-type=multipart/form-data;अपने क्लाइंट में सेट करने की आवश्यकता है।

लेकिन जैसा कि आप जानते हैं कि आप json फॉर्मेट में फाइल नहीं भेज सकते हैं। (जब सामग्री-प्रकार आपके क्लाइंट में अनुप्रयोग / json पर सेट किया जाता है)। जब तक आप बेस 64 प्रारूप का उपयोग नहीं करते हैं।

तो आपके पास दो विकल्प हैं:

  • चलो ModelViewSetऔर ModelSerializerकाम को संभालने और अनुरोध का उपयोग कर भेजेंcontent-type=multipart/form-data;
  • फ़ील्ड को इस ModelSerializerरूप में सेट करें Base64ImageField (or) Base64FileFieldऔर अपने क्लाइंट को फ़ाइल को एन्कोड करने Base64और सेट करने के लिए कहेंcontent-type=application/json

0

models.py

from django.db import models

import uuid

class File(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    file = models.FileField(blank=False, null=False)
    
    def __str__(self):
        return self.file.name

serializers.py

from rest_framework import serializers
from .models import File

class FileSerializer(serializers.ModelSerializer):
    class Meta:
        model = File
        fields = "__all__"

views.py

from django.shortcuts import render
from rest_framework.parsers import FileUploadParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

from .serializers import FileSerializer


class FileUploadView(APIView):
    permission_classes = []
    parser_class = (FileUploadParser,)

    def post(self, request, *args, **kwargs):

      file_serializer = FileSerializer(data=request.data)

      if file_serializer.is_valid():
          file_serializer.save()
          return Response(file_serializer.data, status=status.HTTP_201_CREATED)
      else:
          return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

urls.py

from apps.files import views as FileViews

urlpatterns = [
    path('api/files', FileViews.FileUploadView.as_view()),
]

settings.py

# file uload parameters
MEDIA_URL =  '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

api/filesकिसी form-dataफ़ील्ड में संलग्न अपनी फ़ाइल के साथ पोस्ट अनुरोध भेजें file। फ़ाइल को /mediaफ़ोल्डर में अपलोड किया जाएगा और आईडी और फ़ाइल नाम के साथ एक डीबी रिकॉर्ड जोड़ा जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.