summaryrefslogtreecommitdiff
path: root/tests/modeltests/files/models.py
blob: 67c27b54b5747eee8152e267c4bcc58ac374d656 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""
42. Storing files according to a custom storage system

``FileField`` and its variations can take a ``storage`` argument to specify how
and where files should be stored.
"""

import random
import tempfile
from django.db import models
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage

temp_storage_location = tempfile.mkdtemp()
temp_storage = FileSystemStorage(location=temp_storage_location)

# Write out a file to be used as default content
temp_storage.save('tests/default.txt', ContentFile('default content'))

class Storage(models.Model):
    def custom_upload_to(self, filename):
        return 'foo'

    def random_upload_to(self, filename):
        # This returns a different result each time,
        # to make sure it only gets called once.
        return '%s/%s' % (random.randint(100, 999), filename)

    normal = models.FileField(storage=temp_storage, upload_to='tests')
    custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
    random = models.FileField(storage=temp_storage, upload_to=random_upload_to)
    default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')

__test__ = {'API_TESTS':"""
# Attempting to access a FileField from the class raises a descriptive error
>>> Storage.normal
Traceback (most recent call last):
...
AttributeError: The 'normal' attribute can only be accessed from Storage instances.

# An object without a file has limited functionality.

>>> obj1 = Storage()
>>> obj1.normal
<FieldFile: None>
>>> obj1.normal.size
Traceback (most recent call last):
...
ValueError: The 'normal' attribute has no file associated with it.

# Saving a file enables full functionality.

>>> obj1.normal.save('django_test.txt', ContentFile('content'))
>>> obj1.normal
<FieldFile: tests/django_test.txt>
>>> obj1.normal.size
7
>>> obj1.normal.read()
'content'

# File objects can be assigned to FileField attributes,  but shouldn't get
# committed until the model it's attached to is saved.

>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> obj1.normal = SimpleUploadedFile('assignment.txt', 'content')
>>> dirs, files = temp_storage.listdir('tests')
>>> dirs
[]
>>> files.sort()
>>> files == ['default.txt', 'django_test.txt']
True

>>> obj1.save()
>>> dirs, files = temp_storage.listdir('tests')
>>> files.sort()
>>> files == ['assignment.txt', 'default.txt', 'django_test.txt']
True

# Files can be read in a little at a time, if necessary.

>>> obj1.normal.open()
>>> obj1.normal.read(3)
'con'
>>> obj1.normal.read()
'tent'
>>> '-'.join(obj1.normal.chunks(chunk_size=2))
'co-nt-en-t'

# Save another file with the same name.

>>> obj2 = Storage()
>>> obj2.normal.save('django_test.txt', ContentFile('more content'))
>>> obj2.normal
<FieldFile: tests/django_test_1.txt>
>>> obj2.normal.size
12

# Push the objects into the cache to make sure they pickle properly

>>> from django.core.cache import cache
>>> cache.set('obj1', obj1)
>>> cache.set('obj2', obj2)
>>> cache.get('obj2').normal
<FieldFile: tests/django_test_1.txt>

# Deleting an object deletes the file it uses, if there are no other objects
# still using that file.

>>> obj2.delete()
>>> obj2.normal.save('django_test.txt', ContentFile('more content'))
>>> obj2.normal
<FieldFile: tests/django_test_1.txt>

# Multiple files with the same name get _N appended to them.

>>> objs = [Storage() for i in range(3)]
>>> for o in objs:
...     o.normal.save('multiple_files.txt', ContentFile('Same Content'))
>>> [o.normal for o in objs]
[<FieldFile: tests/multiple_files.txt>, <FieldFile: tests/multiple_files_1.txt>, <FieldFile: tests/multiple_files_2.txt>]
>>> for o in objs:
...     o.delete()

# Default values allow an object to access a single file.

>>> obj3 = Storage.objects.create()
>>> obj3.default
<FieldFile: tests/default.txt>
>>> obj3.default.read()
'default content'

# But it shouldn't be deleted, even if there are no more objects using it.

>>> obj3.delete()
>>> obj3 = Storage()
>>> obj3.default.read()
'default content'

# Verify the fix for #5655, making sure the directory is only determined once.

>>> obj4 = Storage()
>>> obj4.random.save('random_file', ContentFile('random content'))
>>> obj4.random
<FieldFile: .../random_file>

# Clean up the temporary files and dir.
>>> obj1.normal.delete()
>>> obj2.normal.delete()
>>> obj3.default.delete()
>>> obj4.random.delete()

>>> import shutil
>>> shutil.rmtree(temp_storage_location)
"""}