Ticket #5361: filestorage.4.diff
File filestorage.4.diff, 33.2 KB (added by , 17 years ago) |
---|
-
django/core/filestorage/base.py
1 from StringIO import StringIO 2 3 class Backend(object): 4 def get_available_filename(self, filename): 5 # If the filename already exists, keep adding an underscore to the name 6 # of the file until the filename doesn't exist. 7 while self.file_exists(filename): 8 try: 9 dot_index = filename.rindex('.') 10 except ValueError: # filename has no dot 11 filename += '_' 12 else: 13 filename = filename[:dot_index] + '_' + filename[dot_index:] 14 return filename 15 16 def get_absolute_filename(self, filename): 17 return None 18 19 class RemoteFile(StringIO): 20 """Sends files to a remote backend automatically, when necessary.""" 21 22 def __init__(self, data, mode, writer): 23 self._mode = mode 24 self._write_to_backend = writer 25 self._is_dirty = False 26 StringIO.__init__(self, data) 27 28 def write(self, data): 29 if 'w' not in self._mode: 30 raise AttributeError, "File was opened for read-only access." 31 StringIO.write(self, data) 32 self._is_dirty = True 33 34 def close(self): 35 if self._is_dirty: 36 self._write_to_backend(self.getvalue()) 37 StringIO.close(self) 38 -
django/core/filestorage/filesystem.py
1 import datetime 2 import os 3 4 from django.conf import settings 5 from django.utils.encoding import force_unicode, smart_str 6 7 from django.core.filestorage.base import Backend 8 9 class FileSystemBackend(Backend): 10 """Standard filesystem storage""" 11 12 def __init__(self, location='', media_root=None, media_url=None): 13 self.location = location 14 if media_root != None and media_url != None: 15 # Both were provided, so use them 16 pass 17 elif media_root is None and media_url is None: 18 # Neither were provided, so use global settings 19 from django.conf import settings 20 try: 21 media_root = settings.MEDIA_ROOT 22 media_url = settings.MEDIA_URL 23 except AttributeError: 24 raise ImproperlyConfigured, "Media settings not defined." 25 else: 26 # One or the other were provided, but not both 27 raise ImproperlyConfigured, "Both media_root and media_url must be provided." 28 self.media_root = media_root 29 self.media_url = media_url 30 31 def _get_directory_name(self): 32 return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.location)))) 33 34 # The following methods define the Backend API 35 36 def get_absolute_path(self, filename): 37 return os.path.normpath(os.path.join(self.media_root, filename)) 38 39 def get_available_filename(self, filename): 40 from django.utils.text import get_valid_filename 41 f = os.path.join(self._get_directory_name(), get_valid_filename(os.path.basename(filename))) 42 return Backend.get_available_filename(self, os.path.normpath(f)) 43 44 def get_filesize(self, filename): 45 return os.path.getsize(self.get_absolute_path(filename)) 46 47 def get_absolute_url(self, filename): 48 import urlparse 49 return urlparse.urljoin(self.media_url, filename).replace('\\', '/') 50 51 def open(self, filename, mode='rb'): 52 return open(self.get_absolute_path(filename), mode) 53 54 def file_exists(self, filename): 55 return os.path.exists(self.get_absolute_path(filename)) 56 57 def save_file(self, filename, raw_contents): 58 directory = self._get_directory_name() 59 try: # Create the date-based directory if it doesn't exist. 60 os.makedirs(os.path.join(self.media_root, directory)) 61 except OSError: # Directory probably already exists. 62 pass 63 filename = self.get_available_filename(filename) 64 65 # Write the file to disk. 66 fp = open(self.get_absolute_path(filename), 'wb') 67 fp.write(raw_contents) 68 fp.close() 69 70 return filename 71 72 def delete_file(self, filename): 73 file_name = self.get_absolute_path(filename) 74 # If the file exists, delete it from the filesystem. 75 if os.path.exists(file_name): 76 os.remove(file_name) -
django/db/models/base.py
18 18 import types 19 19 import sys 20 20 import os 21 from warnings import warn 21 22 22 23 class ModelBase(type): 23 24 "Metaclass for all models" … … 366 367 return getattr(self, cachename) 367 368 368 369 def _get_FIELD_filename(self, field): 369 if getattr(self, field.attname): # value is not blank 370 return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname)) 371 return '' 370 warn("Use instance.%s.open() if you need access to the file." % field.attname, DeprecationWarning) 371 return field.backend._get_absolute_path(self.__dict__[field.attname]) 372 372 373 373 def _get_FIELD_url(self, field): 374 if getattr(self, field.attname): # value is not blank 375 import urlparse 376 return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/') 377 return '' 374 warn("Use instance.%s.get_absolute_url()." % field.attname, DeprecationWarning) 375 return getattr(self, field.attname).get_absolute_url() 378 376 379 377 def _get_FIELD_size(self, field): 380 return os.path.getsize(self._get_FIELD_filename(field)) 378 warn("Use instance.%s.get_filesize()." % field.attname, DeprecationWarning) 379 return getattr(self, field.attname).get_filesize() 381 380 382 381 def _save_FIELD_file(self, field, filename, raw_contents, save=True): 383 directory = field.get_directory_name() 384 try: # Create the date-based directory if it doesn't exist. 385 os.makedirs(os.path.join(settings.MEDIA_ROOT, directory)) 386 except OSError: # Directory probably already exists. 387 pass 388 filename = field.get_filename(filename) 382 warn("Use instance.%s.save_file()." % field.attname, DeprecationWarning) 383 return getattr(self, field.attname).save_file(filename, raw_contents, save) 389 384 390 # If the filename already exists, keep adding an underscore to the name of391 # the file until the filename doesn't exist.392 while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):393 try:394 dot_index = filename.rindex('.')395 except ValueError: # filename has no dot396 filename += '_'397 else:398 filename = filename[:dot_index] + '_' + filename[dot_index:]399 400 # Write the file to disk.401 setattr(self, field.attname, filename)402 403 full_filename = self._get_FIELD_filename(field)404 fp = open(full_filename, 'wb')405 fp.write(raw_contents)406 fp.close()407 408 # Save the width and/or height, if applicable.409 if isinstance(field, ImageField) and (field.width_field or field.height_field):410 from django.utils.images import get_image_dimensions411 width, height = get_image_dimensions(full_filename)412 if field.width_field:413 setattr(self, field.width_field, width)414 if field.height_field:415 setattr(self, field.height_field, height)416 417 # Save the object because it has changed unless save is False418 if save:419 self.save()420 421 _save_FIELD_file.alters_data = True422 423 385 def _get_FIELD_width(self, field): 424 return self._get_image_dimensions(field)[0] 386 warn("Use instance.%s.get_width()." % field.attname, DeprecationWarning) 387 return getattr(self, field.attname).get_width() 425 388 426 389 def _get_FIELD_height(self, field): 427 return self._get_image_dimensions(field)[1] 390 warn("Use instance.%s.get_height()." % field.attname, DeprecationWarning) 391 return getattr(self, field.attname).get_height() 428 392 429 def _get_image_dimensions(self, field):430 cachename = "__%s_dimensions_cache" % field.name431 if not hasattr(self, cachename):432 from django.utils.images import get_image_dimensions433 filename = self._get_FIELD_filename(field)434 setattr(self, cachename, get_image_dimensions(filename))435 return getattr(self, cachename)436 437 393 ############################################ 438 394 # HELPER FUNCTIONS (CURRIED MODEL METHODS) # 439 395 ############################################ -
django/db/models/fields/__init__.py
704 704 defaults.update(kwargs) 705 705 return super(EmailField, self).formfield(**defaults) 706 706 707 class File(object): 708 def __init__(self, obj, field, filename): 709 self.obj = obj 710 self.field = field 711 self.backend = field.backend 712 self.filename = filename 713 714 def __str__(self): 715 return self.filename 716 717 def get_absolute_path(self): 718 return self.backend.get_absolute_path(self.filename) 719 720 def get_absolute_url(self): 721 return self.backend.get_absolute_url(self.filename) 722 723 def get_filesize(self): 724 if not hasattr(self, '_filesize'): 725 self._filesize = self.backend.get_filesize(self.filename) 726 return self._filesize 727 728 def open(self, mode='rb'): 729 return self.backend.open(self.filename, mode) 730 731 def save_file(self, filename, raw_contents, save=True): 732 self.filename = self.backend.save_file(filename, raw_contents) 733 734 # Update the filesize cache 735 self._filesize = len(raw_contents) 736 737 # Save the object because it has changed, unless save is False 738 if save: 739 self.obj.save() 740 741 class FileProxy(object): 742 def __init__(self, field): 743 self.field = field 744 self.cache_name = self.field.get_cache_name() 745 746 def __get__(self, instance=None, owner=None): 747 if instance is None: 748 raise AttributeError, "%s can only be accessed from %s instances." % (self.field.attname, self.owner.__name__) 749 return getattr(instance, self.cache_name) 750 751 def __set__(self, instance, value): 752 if hasattr(instance, self.cache_name): 753 raise AttributeError, "%s can not be set in this manner." % self.field.attname 754 instance.__dict__[self.field.attname] = value 755 attr = self.field.attr_class(instance, self.field, value) 756 setattr(instance, self.cache_name, attr) 757 707 758 class FileField(Field): 708 def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs): 709 self.upload_to = upload_to 759 attr_class = File 760 761 def __init__(self, verbose_name=None, name=None, upload_to='', backend=None, **kwargs): 762 if backend is None: 763 from django.core.filestorage.filesystem import FileSystemBackend 764 backend = FileSystemBackend(location=upload_to) 765 self.backend = self.upload_to = backend 710 766 Field.__init__(self, verbose_name, name, **kwargs) 711 767 712 768 def get_db_prep_save(self, value): … … 714 770 # Need to convert UploadedFile objects provided via a form to unicode for database insertion 715 771 if value is None: 716 772 return None 717 return unicode(value )773 return unicode(value.filename) 718 774 719 775 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): 720 776 field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow) … … 754 810 755 811 def contribute_to_class(self, cls, name): 756 812 super(FileField, self).contribute_to_class(cls, name) 813 setattr(cls, self.attname, FileProxy(self)) 757 814 setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filename, field=self)) 758 815 setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self)) 759 816 setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self)) 760 817 setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_contents, save=True: instance._save_FIELD_file(self, filename, raw_contents, save)) 761 818 dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls) 762 819 763 def delete_file(self, instance): 764 if getattr(instance, self.attname): 765 file_name = getattr(instance, 'get_%s_filename' % self.name)() 766 # If the file exists and no other object of this type references it, 767 # delete it from the filesystem. 768 if os.path.exists(file_name) and \ 769 not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}): 770 os.remove(file_name) 820 def delete_file(self, instance, sender): 821 filename = getattr(instance, self.attname).filename 822 # If no other object of this type references the file, 823 # delete it from the backend. 824 if not sender._default_manager.filter(**{self.name: filename}): 825 self.backend.delete_file(filename) 771 826 772 827 def get_manipulator_field_objs(self): 773 828 return [oldforms.FileUploadField, oldforms.HiddenField] … … 778 833 def save_file(self, new_data, new_object, original_object, change, rel, save=True): 779 834 upload_field_name = self.get_manipulator_field_names('')[0] 780 835 if new_data.get(upload_field_name, False): 781 func = getattr(new_object, 'save_%s_file' % self.name)782 836 if rel: 783 f unc(new_data[upload_field_name][0]["filename"], new_data[upload_field_name][0]["content"], save)837 field = new_data[upload_field_name][0] 784 838 else: 785 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save) 839 field = new_data[upload_field_name] 840 getattr(new_object, self.attname).save_file(field["filename"], field["content"], save) 786 841 787 def get_directory_name(self):788 return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))789 790 def get_filename(self, filename):791 from django.utils.text import get_valid_filename792 f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))793 return os.path.normpath(f)794 795 842 def save_form_data(self, instance, data): 796 843 if data: 797 getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)844 getattr(instance, self.attnamename).save_file(data.filename, data.content, save=False) 798 845 799 846 def formfield(self, **kwargs): 800 847 defaults = {'form_class': forms.FileField} … … 824 871 defaults.update(kwargs) 825 872 return super(FloatField, self).formfield(**defaults) 826 873 874 class ImageFile(File): 875 def get_width(self): 876 return self._get_image_dimensions()[0] 877 878 def get_height(self): 879 return self._get_image_dimensions()[1] 880 881 def _get_image_dimensions(self): 882 if not hasattr(self, '_dimensions_cache'): 883 from django.utils.images import get_image_dimensions 884 self._dimensions_cache = get_image_dimensions(self.open()) 885 return self._dimensions_cache 886 887 def save_file(self, filename, raw_contents, save=True): 888 super(ImageFile, self).save_file(filename, raw_contents, save) 889 890 # Update the cache for image dimensions 891 from django.utils.images import get_image_dimensions 892 from cStringIO import StringIO 893 self._dimensions_cache = get_image_dimensions(StringIO(raw_contents)) 894 827 895 class ImageField(FileField): 896 attr_class = ImageFile 897 828 898 def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs): 829 899 self.width_field, self.height_field = width_field, height_field 830 900 FileField.__init__(self, verbose_name, name, **kwargs) … … 842 912 setattr(cls, 'get_%s_height' % self.name, curry(cls._get_FIELD_height, field=self)) 843 913 844 914 def save_file(self, new_data, new_object, original_object, change, rel, save=True): 845 FileField.save_file(self, new_data, new_object, original_object, change, rel, save)846 915 # If the image has height and/or width field(s) and they haven't 847 916 # changed, set the width and/or height field(s) back to their original 848 917 # values. 849 if change and (self.width_field or self.height_field) and save: 850 if self.width_field: 851 setattr(new_object, self.width_field, getattr(original_object, self.width_field)) 852 if self.height_field: 853 setattr(new_object, self.height_field, getattr(original_object, self.height_field)) 854 new_object.save() 918 if self.width_field or self.height_field: 919 if original_object and not change: 920 if self.width_field: 921 setattr(new_object, self.width_field, getattr(original_object, self.width_field)) 922 if self.height_field: 923 setattr(new_object, self.height_field, getattr(original_object, self.height_field)) 924 else: 925 from cStringIO import StringIO 926 from django.utils.images import get_image_dimensions 855 927 928 upload_field_name = self.get_manipulator_field_names('')[0] 929 if rel: 930 field = new_data[upload_field_name][0] 931 else: 932 field = new_data[upload_field_name] 933 934 # Get the width and height from the raw content to avoid extra 935 # unnecessary trips to the file backend. 936 width, height = get_image_dimensions(StringIO(field["content"])) 937 938 if self.width_field: 939 setattr(new_object, self.width_field, width) 940 if self.height_field: 941 setattr(new_object, self.height_field, height) 942 FileField.save_file(self, new_data, new_object, original_object, change, rel, save) 943 856 944 def formfield(self, **kwargs): 857 945 defaults = {'form_class': forms.ImageField} 858 946 defaults.update(kwargs) -
django/utils/images.py
6 6 7 7 import ImageFile 8 8 9 def get_image_dimensions( path):10 """Returns the (width, height) of an image at a givenpath."""9 def get_image_dimensions(file_or_path): 10 """Returns the (width, height) of an image, given an open file or a path.""" 11 11 p = ImageFile.Parser() 12 fp = open(path, 'rb') 12 if hasattr(file_or_path, 'read'): 13 fp = file_or_path 14 else: 15 fp = open(file_or_path, 'rb') 13 16 while 1: 14 17 data = fp.read(1024) 15 18 if not data: … … 19 22 return p.image.size 20 23 break 21 24 fp.close() 22 return None 25 return None 26 No newline at end of file -
docs/db-api.txt
1871 1871 get_FOO_filename() 1872 1872 ------------------ 1873 1873 1874 **Deprecated in Django development version. See `managing files` for the new, 1875 preferred method for dealing with files.** 1876 1874 1877 For every ``FileField``, the object will have a ``get_FOO_filename()`` method, 1875 1878 where ``FOO`` is the name of the field. This returns the full filesystem path 1876 1879 to the file, according to your ``MEDIA_ROOT`` setting. … … 1881 1884 get_FOO_url() 1882 1885 ------------- 1883 1886 1887 **Deprecated in Django development version. See `managing files` for the new, 1888 preferred method for dealing with files.** 1889 1884 1890 For every ``FileField``, the object will have a ``get_FOO_url()`` method, 1885 1891 where ``FOO`` is the name of the field. This returns the full URL to the file, 1886 1892 according to your ``MEDIA_URL`` setting. If the value is blank, this method … … 1889 1895 get_FOO_size() 1890 1896 -------------- 1891 1897 1898 **Deprecated in Django development version. See `managing files` for the new, 1899 preferred method for dealing with files.** 1900 1892 1901 For every ``FileField``, the object will have a ``get_FOO_size()`` method, 1893 1902 where ``FOO`` is the name of the field. This returns the size of the file, in 1894 1903 bytes. (Behind the scenes, it uses ``os.path.getsize``.) … … 1896 1905 save_FOO_file(filename, raw_contents) 1897 1906 ------------------------------------- 1898 1907 1908 **Deprecated in Django development version. See `managing files` for the new, 1909 preferred method for dealing with files.** 1910 1899 1911 For every ``FileField``, the object will have a ``save_FOO_file()`` method, 1900 1912 where ``FOO`` is the name of the field. This saves the given file to the 1901 1913 filesystem, using the given filename. If a file with the given filename already … … 1905 1917 get_FOO_height() and get_FOO_width() 1906 1918 ------------------------------------ 1907 1919 1920 **Deprecated in Django development version. See `managing files` for the new, 1921 preferred method for dealing with files.** 1922 1908 1923 For every ``ImageField``, the object will have ``get_FOO_height()`` and 1909 1924 ``get_FOO_width()`` methods, where ``FOO`` is the name of the field. This 1910 1925 returns the height (or width) of the image, as an integer, in pixels. -
docs/files.txt
1 ============== 2 Managing files 3 ============== 4 5 When dealing with files, Django provides a number of features to make this task 6 easier and more portable. A backend protocol is available to allow files to be 7 stored in a variety of locations, and a special object is provided to allow 8 models to make use of this protocol, without having to worry about which storage 9 system is being used. 10 11 Using files in models 12 ===================== 13 14 When accessing a ``FileField`` attached to a model, a special object provides 15 access to the file and information about it. 16 17 get_absolute_path() 18 ------------------- 19 20 Returns the absolute path to the file's location on a local filesystem. For 21 backends which do not store files locally, this will return `None`. 22 23 get_absolute_url() 24 ------------------ 25 26 Provides a URL where the content of the file can be retrieved. Therefore, 27 returned from this method is suitable for use as the destination of a link to 28 the file. 29 30 get_filesize() 31 -------------- 32 33 Returns the size of the file, as an integer. 34 35 open(mode='rb') 36 --------------- 37 38 Returns an open file object, providing read or write access to the file's 39 contents. The ``mode`` argument allows the same values as Python's standard 40 ``open()`` function. 41 42 save_file(filename, raw_contents, save=True) 43 -------------------------------------------- 44 45 Saves a new file with the filename and contents provided. This will not replace 46 the existing file, but will create a new file and update the object to point to 47 it. The optional ``save`` argument dictates whether the model instance will be 48 saved to the database immediately. 49 50 get_width() and get_height() 51 ---------------------------- 52 53 When using an ``ImageField``, these two methods will be available, providing 54 easy access to the dimensions of the image. 55 56 Example 57 ------- 58 59 Consider the following model, using an ``ImageField`` to store a product photo:: 60 61 class Product(models.Model): 62 name = models.CharField(maxlength=255) 63 price = models.DecimalField(max_digits=5, decimal_places=2) 64 photo = models.ImageField(upload_to='product_photos') 65 66 Your views can then use the ``photo`` attribute with the functions described 67 above, as follows:: 68 69 >>> car = Product.object.get(name="'57 Chevy") 70 >>> car.photo.get_absolute_url() 71 '/products/photo/123.jpg' 72 >>> car.photo.get_width(), car.photo.get_height() 73 (800, 600) 74 75 Specifying a storage backend 76 ============================ 77 78 When using a storage backend, supply whatever options are appropriate for 79 that backend when creating a new object. Details on the requirements for the 80 included backends can be found below. Then pass that object as the ``backend`` 81 argument to a ``FileField``. 82 83 If using the ``FileSystemBackend``, it is not necessary to create a backend 84 object explicitly. Simply supplying the ``upload_to`` argument will create the 85 backend object automatically. 86 87 See the ```FileField`` documentation`_ for more information on using the field. 88 89 .. _FileField documentation: ../model-api/#filefield 90 91 For example, the following code will explicitly use the ``FileSystemBackend``:: 92 93 from django.db import models 94 from django.core.filestorage.filesystem import FileSystemBackend 95 96 fs = FileSystemBackend(location='product_photos') 97 98 class Product(models.Model): 99 name = models.CharField(maxlength=255) 100 price = models.DecimalField(max_digits=5, decimal_places=2) 101 photo = models.ImageField(backend=fs) 102 103 Available backends 104 ================== 105 106 Only one storage backend is supplied in the official Django distribution, but 107 more may be available elsewhere. The documentation for the ``FileSystemBackend`` 108 requirements will not necessarily be the same for other backends, so see the 109 documentation included with the backend if you use a different one. 110 111 FileSystemBackend 112 ----------------- 113 114 This backend stores files on the system's standard filesystem. It requires just 115 one argument, while two more are optional: 116 117 ====================== =================================================== 118 Argument Description 119 ====================== =================================================== 120 ``location`` A local filesystem path that will be appended to 121 your ``MEDIA_ROOT`` setting to determine the 122 output of the ``get_<fieldname>_url()`` helper 123 function. 124 ``media_root`` Absolute path to the directory that holds the files 125 for this backend. If omitted, it will be set to the 126 value of your ``MEDIA_ROOT`` setting. 127 ``media_url`` URL that serves the files stored in this backend. 128 If omitted, it will default to the value of your 129 ``MEDIA_URL`` setting. 130 ====================== =================================================== 131 132 Writing a storage backend 133 ========================= 134 135 While filesystem storage is suitable for most needs, there are many other file 136 uses that require access to different storage mechanisms. In order to access 137 alternate storage systems, it's fairly simple to write a new storage backend, 138 creating a wrapper around whatever libraries are used to access your files. 139 140 Storage backends extend ``django.core.filestorage.Backend`` and provide a set of 141 methods to do the work of actually interfacing the the storage system. 142 143 get_available_filename(filename) 144 -------------------------------- 145 146 Returns a filename that is available in the storage mechanism. The ``filename`` 147 argument is the name originally given to the file, so this method may take that 148 name into account when generating a new filename. 149 150 This method is provided on the base ``Backend`` class, which simply appends 151 underscores to the filename until it finds 152 153 get_filesize(filename) 154 ---------------------- 155 156 Returns the total size of the file referenced by ``filename``, as an integer. 157 158 get_absolute_url(filename) 159 -------------------------- 160 161 Provides a URL where the contents of the file referenced by ``filename`` can be 162 accessed. 163 164 file_exists(filename) 165 --------------------- 166 167 Returns ``True`` or ``False, indicating whether there is already a file present 168 at the location referenced by``filename``. The ``get_available_filename()`` uses 169 this method to determine whether a file is available, before trying a new name. 170 171 open(filename, mode='rb') 172 ------------------------- 173 174 Returns an open file, or file-like, object to provide access to the contents of 175 the file referenced by ``filename``. The ``mode`` argument allows the same 176 values as Python's standard ``open()`` function. 177 178 The object returned should function like a standard `file object`_, but there is 179 a class available, ``django.core.filestorage.RemoteFile``, which makes this task 180 easier. Creating an instance of this object requires three arguments, which are 181 desribed below. 182 183 ====================== =================================================== 184 Argument Description 185 ====================== =================================================== 186 ``data`` The raw content of the file. 187 ``mode`` The access mode that was passed to the ``open()`` 188 method. 189 ``writer`` A function that will be used to write the contents 190 to the backend-specific storage mechanism. The 191 function provided here will need to take a single 192 argument, which will be the raw content to be 193 written to the file. 194 ====================== =================================================== 195 196 .. _file object: http://docs.python.org/lib/bltin-file-objects.html 197 198 save_file(filename, raw_contents) 199 --------------------------------- 200 201 Saves a new file using the backend-specific storage mechanism. The ``filename`` 202 passed to this method will be the original file's name, and might not be 203 available in the actual storage system. 204 205 This method is therefore responsible for identifying an available filename, 206 usually using ``get_available_filename()`` method described above. This method 207 must then return the actual filename that was used to store the file. 208 209 delete_file(filename) 210 --------------------- 211 212 Deletes the file referenced by ``filename``. If the file does not already exist, 213 this method should simply return without throwing an error. 214 No newline at end of file -
docs/model-api.txt
230 230 ``FileField`` 231 231 ~~~~~~~~~~~~~ 232 232 233 A file-upload field. Has one **required** argument:233 A file-upload field. **Requires** exactly one of the following two arguments: 234 234 235 235 ====================== =================================================== 236 236 Argument Description 237 237 ====================== =================================================== 238 238 ``upload_to`` A local filesystem path that will be appended to 239 239 your ``MEDIA_ROOT`` setting to determine the 240 output of the ``get_<fieldname>_url()`` helper 241 function. 240 final storage destination. If this argument is 241 supplied, the storage backend will default to 242 ``FileSystemBackend``. 243 ``backend`` **New in Django development version** 244 245 A storage backend object, which handles the storage 246 and retrieval of your files. See `managing files`_ 247 for details on how to provide this object. 242 248 ====================== =================================================== 243 249 244 This path may contain `strftime formatting`_, which will be replaced by the 245 date/time of the file upload (so that uploaded files don't fill up the given 246 directory). 250 .. _managing files: ../files/ 247 251 252 The ``upload_to`` path may contain `strftime formatting`_, which will be 253 replaced by the date/time of the file upload (so that uploaded files don't fill 254 up the given directory). 255 248 256 The admin represents this field as an ``<input type="file">`` (a file-upload 249 257 widget). 250 258 251 Using a ``FileField`` or an ``ImageField`` (see below) in a model takes a few252 s teps:259 Using a ``FileField`` or an ``ImageField`` (see below) in a model without a 260 specified backend takes a few steps: 253 261 254 262 1. In your settings file, you'll need to define ``MEDIA_ROOT`` as the 255 263 full path to a directory where you'd like Django to store uploaded