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