Django के FileField को किसी मौजूदा फ़ाइल पर सेट करें


89

मेरे पास डिस्क पर एक मौजूदा फ़ाइल है (जो /folder/file.txt) और Django में एक फ़ाइलफ़िल्ड मॉडल फ़ील्ड है।

जब मैं करता हूं

instance.field = File(file('/folder/file.txt'))
instance.save()

यह file_1.txt(अगली बार जब _2, आदि) के रूप में फ़ाइल को फिर से बचाता है ।

मैं समझता हूं कि क्यों, लेकिन मैं इस व्यवहार को नहीं चाहता - मुझे पता है कि जिस फ़ाइल को मैं चाहता हूं, वह क्षेत्र वास्तव में मेरे साथ इंतजार कर रहा है, और मैं सिर्फ Django को इंगित करना चाहता हूं।

कैसे?


1
सुनिश्चित नहीं हैं कि आप Django या उपवर्ग को संशोधित किए बिना जो चाहें प्राप्त कर सकते हैं FileField। जब भी FileFieldसहेजा जाता है, फ़ाइल की एक नई प्रतिलिपि बनाई जाती है। इससे बचने के लिए विकल्प जोड़ना काफी सरल होगा।
माइकल मिओर

अच्छी तरह से हाँ, ऐसा लगता है कि मुझे एक उप-वर्ग को जोड़ना और जोड़ना है। मैं इस सरल कार्य के लिए अतिरिक्त टेबल बनाने के लिए तैयार नहीं हूं
गार्ड

1
फ़ाइल को किसी अन्य स्थान पर रखें, इस पथ के साथ अपना फ़ील्ड बनाएं, इसे सहेजें और फिर आपके पास अपलोड_टो गंतव्य में फ़ाइल है।
23

जवाबों:


22

यदि आप इसे स्थायी रूप से करना चाहते हैं, तो आपको अपना खुद का FileStorage वर्ग बनाने की आवश्यकता है

import os
from django.conf import settings
from django.core.files.storage import FileSystemStorage

class MyFileStorage(FileSystemStorage):

    # This method is actually defined in Storage
    def get_available_name(self, name):
        if self.exists(name):
            os.remove(os.path.join(settings.MEDIA_ROOT, name))
        return name # simply returns the name passed

अब आपके मॉडल में, आप अपने संशोधित MyFileStorage का उपयोग करते हैं

from mystuff.customs import MyFileStorage

mfs = MyFileStorage()

class SomeModel(model.Model):
   my_file = model.FileField(storage=mfs)

ओह, होनहार लग रहा है। FileField का कोड cuase थोड़े गैर-सहज ज्ञान युक्त है
गार्ड '

लेकिन ... क्या प्रति-अनुरोध के आधार पर भंडारण को बदलना संभव है, जैसे: example.field.storage = mfs; inst.field.save (नाम, फ़ाइल); लेकिन यह मेरे कोड की एक अलग शाखा में नहीं कर रहा हूँ
गार्ड

2
नहीं, चूंकि भंडारण इंजन मॉडल से बंधा हुआ है। आप अपनी फ़ाइल पथ को या तो FilePathFieldसादे पाठ के रूप में संग्रहीत करके इस सब से बच सकते हैं ।
बुरहान खालिद

आप सिर्फ एक नाम नहीं लौटा सकते। आपको पहले मौजूदा फ़ाइल को निकालने की आवश्यकता है।
अलेक्जेंडर श्पिंडलर

124

बस instance.field.nameअपनी फ़ाइल के पथ पर सेट करें

जैसे

class Document(models.Model):
    file = FileField(upload_to=get_document_path)
    description = CharField(max_length=100)


doc = Document()
doc.file.name = 'path/to/file'  # must be relative to MEDIA_ROOT
doc.file
<FieldFile: path/to/file>

15
अपने से सापेक्ष पथ MEDIA_ROOT, वह है।
मंगल

7
इस उदाहरण में, मुझे लगता है कि आप भी कर सकते हैंdoc.file = 'path/to/file'
एंड्रयू स्विहार्ट


5

स्वयं का संग्रहण वर्ग लिखना सही है। हालांकि get_available_nameओवरराइड करने का सही तरीका नहीं है।

get_available_nameकहा जाता है जब Django एक ही नाम के साथ एक फ़ाइल देखता है और एक नया उपलब्ध फ़ाइल नाम प्राप्त करने की कोशिश करता है। यह ऐसा तरीका नहीं है जो नाम बदलने का कारण बनता है। विधि के कारण होता है कि _save। में टिप्पणियाँ _saveबहुत अच्छी है और आप आसानी से पा सकते हैं कि यह झंडे के साथ लिखने के लिए फ़ाइल खोलता है os.O_EXCLजो OSError फेंक देगा यदि वही फ़ाइल नाम पहले से मौजूद है। Django इस त्रुटि को तब कॉल करता हैget_available_name एक नया नाम प्राप्त करने के लिए है।

इसलिए मुझे लगता है कि _saveझंडा के बिना os.open () को ओवरराइड और कॉल करने का सही तरीका है os.O_EXCL। संशोधन काफी सरल है, लेकिन विधि थोड़ी लंबी है इसलिए मैं इसे यहां पेस्ट नहीं करता हूं। अगर आपको और मदद चाहिए तो मुझे बताएं :)


यह कोड की 50 पंक्तियाँ हैं जिन्हें आपको कॉपी करना है, जो बहुत बुरा है। ओवरराइडिंग get_available_name लगता है कि अधिक पृथक, छोटा और भविष्य के लिए Django के नए संस्करणों के उन्नयन के लिए अधिक सुरक्षित है,
माइकल जेंडिन

2
केवल ओवरराइडिंग की समस्या get_available_nameहै जब आप एक ही नाम के साथ एक फ़ाइल अपलोड करते हैं, तो सर्वर एक अंतहीन लूप में पहुंच जाएगा। चूंकि _saveफ़ाइल नाम की जाँच करता है और एक नया प्राप्त करने का निर्णय लेता है लेकिन फिर get_available_nameभी डुप्लिकेट एक को वापस करता है। इसलिए आपको दोनों को ओवरराइड करने की आवश्यकता है।
X1a0

1
ओह, हम इस प्रश्न पर दो प्रश्नों में चर्चा कर रहे हैं, लेकिन केवल अब मैंने देखा कि वे थोड़े भिन्न हैं) इसलिए मैं उस प्रश्न में सही हूं, और आप इस में हैं)
माइकल जेंडिन

1

मेरे साथ भी ठीक यही समस्या आई! तब मुझे अहसास हुआ कि मेरे मॉडल्स ऐसा कर रहे थे। उदाहरण मैं अपने मॉडल इस तरह था:

class Tile(models.Model):
  image = models.ImageField()

फिर, मैं चाहता था कि डिस्क में एक ही फ़ाइल को संदर्भित करने वाला एक से अधिक टाइल हो! जिस तरह से मुझे हल करने के लिए मिला वह मेरी मॉडल संरचना को इस में बदल गया था:

class Tile(models.Model):
  image = models.ForeignKey(TileImage)

class TileImage(models.Model):
  image = models.ImageField()

जिसके बाद मुझे एहसास हुआ कि इसे और अधिक समझ में आता है, क्योंकि अगर मैं चाहता हूं कि उसी फ़ाइल को अधिक सहेजा जाए, तो मेरे डीबी में मुझे इसके लिए एक और तालिका बनानी होगी!

मुझे लगता है कि आप अपनी समस्या को भी हल कर सकते हैं, बस उम्मीद है कि आप मॉडल बदल सकते हैं!

संपादित करें

इसके अलावा, मुझे लगता है कि आप इस तरह के लिए एक अलग भंडारण का उपयोग कर सकते हैं: SymlinkOrCopyStorage

http://code.welldev.org/django-storages/src/11bef0c2a410/storages/backends/symlinkorcopy.py


आपके मामले में समझदारी है, मेरी नहीं। मैं इसे कई बार संदर्भित नहीं करना चाहता। मैं एक फ़ाइल का संदर्भ देने वाली एक वस्तु बनाता हूं, फिर मुझे एहसास होता है कि अन्य अटेंडरों में त्रुटियां हैं, और मैं निर्माण फॉर्म को फिर से खोल देता हूं। इसके पुनरुत्थान पर मैं उस फ़ाइल को ढीला नहीं करना चाहता जो पहले से ही डिस्क पर सहेजी गई है
गार्ड

इसलिए मुझे लगता है कि आप मेरे दृष्टिकोण का उपयोग कर सकते हैं! क्योंकि आपके पास एक टेबल फॉर्म फ़िले होगा जो आपके पास केवल तभी फाइल रखेगा! तब आपके फॉर्म टेबल में आपको उस फ़ाइल के लिए एक FK होगा! तो आप उसी फ़ाइल के लिए नए फॉर्म बदल / बना सकते हैं! (btw मैं अपने मुख्य उदाहरण में FK के क्रम को बदल रहा हूं)
आर्थर नेव्स

यदि आप अपने डोमेन (मॉडल) को अपनी पोस्ट में पोस्ट करना चाहते हैं! मेरे पास एक बेहतर विचारधारा हो सकती है!
आर्थर नेव्स

डोमेन वास्तव में मायने नहीं रखता है - मेरे पास इसके साथ जुड़े फोटो के साथ एक मॉडल है, और मेरे पास कस्टम संपादन स्क्रीन है। एक बार अपलोड होने के बाद मैं चाहता हूं कि फोटो सर्वर पर बनी रहे, लेकिन मैं वास्तव में एक अलग मॉडल, टेबल और एफके लुकिंग को केवल इसलिए पसंद नहीं करता हूं, क्योंकि आप एक फ्रेमवर्क लिमिट दिखते हैं
गार्ड

यहाँ मुझे लगता है कि जब आप django में एक FileField को बचाने की वजह से सीमा, हमेशा यह Django भंडारण के माध्यम से गुजरता है! तो यह समझ में नहीं आता तुम सिर्फ एक फ़ाइल पथ मजबूर! यह भी कैसे Django पता होना चाहिए कि फ़ाइल पहले से ही पथ में मौजूद है? एक और तरीका जो आप उपयोग कर सकते हैं वह है इसके बजाय FilePathField का उपयोग करना! तो आप बस अपने DB में पथ सेट कर सकते हैं और लुकअप कर सकते हैं जिस तरह से आपको लगता है कि सबसे अच्छा है!
आर्थर नेव्स

1

आपको अपने स्वयं के भंडारण को परिभाषित करना चाहिए, इसे फाइलसिस्टमस्टोरेज से विरासत में मिला, और ओवरराइड करें OS_OPEN_FLAGS वर्ग विशेषता और get_available_name()विधि को :

Django संस्करण: 3.1

परियोजना / कोर / फ़ाइलें / भंडार / बैकेंड / local.py

import os

from django.core.files.storage import FileSystemStorage


class OverwriteStorage(FileSystemStorage):
    """
    FileSystemStorage subclass that allows overwrite the already existing
    files.
    
    Be careful using this class, as user-uploaded files will overwrite
    already existing files.
    """

    # The combination that don't makes os.open() raise OSError if the
    # file already exists before it's opened.
    OS_OPEN_FLAGS = os.O_WRONLY | os.O_TRUNC | os.O_CREAT | getattr(os, 'O_BINARY', 0)

    def get_available_name(self, name, max_length=None):
        """
        This method will be called before starting the save process.
        """
        return name

अपने मॉडल में, अपने कस्टम ओवरराइटसाइट का उपयोग करें

MyApp / models.py

from core.files.storages.backends.local import OverwriteStorage


class MyModel(model.Model):
   my_file = model.FileField(storage=OverwriteStorage)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.