jfm / django-stockphoto (http://carcosa.net/jason/software/django/stockphoto/)
Stockphoto is a photogallery application written using the Django web application framework. It is designed to integrate into existing dynamic websites built with Django, to be easy to install, and to have few prerequisites, both in terms of third-party modules and in terms of expectations about site layout. It attempts to make maximum use of built-in Django facilities (authentication, admin pages, generic views) as much as possible in order to provide the simplest possible photogallery application while providing a reasonably full set of features.
$ hg clone http://bitbucket.org/jfm/django-stockphoto/
| commit 40: | fc6926e480b1 |
| parent 39: | c8148beb8202 |
| branch: | default |
Changed (Δ252 bytes):
stockphoto/templates/stockphoto/import_form.html (2 lines added, 2 lines removed)
stockphoto/views.py (46 lines added, 56 lines removed)
Up to file-list stockphoto/templates/stockphoto/import_form.html:
17 |
17 |
</span><br/> |
18 |
18 |
{% endif %} |
19 |
19 |
|
20 |
<label class="fortextinput" for="id_zip |
|
20 |
<label class="fortextinput" for="id_zip_file"> |
|
21 |
21 |
ZIP archive to upload: |
22 |
22 |
</label> |
23 |
{{ form.zip |
|
23 |
{{ form.zip_file }}<br/> |
|
24 |
24 |
|
25 |
25 |
{%if form.photographer.errors %} |
26 |
26 |
<span style="color: red;"> |
Up to file-list stockphoto/views.py:
| … | … | @@ -43,9 +43,9 @@ from datetime import datetime |
43 |
43 |
from tempfile import NamedTemporaryFile, mkdtemp |
44 |
44 |
import Image |
45 |
45 |
try: |
46 |
|
|
46 |
from cStringIO import StringIO |
|
47 |
47 |
except ImportError: |
48 |
|
|
48 |
from StringIO import StringIO |
|
49 |
49 |
|
50 |
50 |
# Handling settings here |
51 |
51 |
try: |
| … | … | @@ -54,27 +54,27 @@ except AttributeError: |
54 |
54 |
STOCKPHOTO_BASE = 'stockphoto' |
55 |
55 |
|
56 |
56 |
# models |
57 |
from |
|
57 |
from models import Gallery, Photo |
|
58 |
58 |
|
59 |
59 |
# views |
60 |
60 |
|
61 |
class ImportManipulator(forms.Manipulator): |
|
62 |
def __init__(self): |
|
63 |
self.fields = ( |
|
64 |
forms.FileUploadField(field_name="zipfile", |
|
65 |
is_required=True, |
|
66 |
validator_list=[self.valid_zipfile,]), |
|
67 |
forms.TextField(field_name="photographer"), |
|
68 |
forms.DateField(field_name="date"), |
|
69 |
) |
|
70 |
def valid_zipfile(self, field_data, all_data): |
|
71 |
zip_file = StringIO(field_data['content']) |
|
72 |
zip = zipfile.ZipFile(zip_file) |
|
73 |
return not zip.testzip() |
|
61 |
class ZipFileField(forms.FileField): |
|
62 |
def __init__(self, *args, **kwargs): |
|
63 |
super(forms.FileField, self).__init__(*args, **kwargs) |
|
64 |
def clean(self, data, initial=None): |
|
65 |
super(FileField, self).clean(initial or data) |
|
66 |
zip_file = zipfile.ZipFile(data) |
|
67 |
if zip_file.testzip(): |
|
68 |
raise forms.ValidationError(self.error_messages['invalid']) |
|
69 |
return data |
|
74 |
70 |
|
71 |
class ImportForm(forms.Form): |
|
72 |
zip_file = forms.ZipFileField(required=True) |
|
73 |
photographer = forms.TextField() |
|
74 |
date = forms.DateField() |
|
75 |
75 |
|
76 |
76 |
|
77 |
||
77 |
@permission_required('gallery.add_photo') |
|
78 |
78 |
def import_photos(request, thegallery): |
79 |
79 |
"""Import a batch of photographs uploaded by the user. |
80 |
80 |
|
| … | … | @@ -100,17 +100,12 @@ def import_photos(request, thegallery): |
100 |
100 |
if not request.user.has_perm('gallery.add_photo'): |
101 |
101 |
return http.HttpResponseForbidden("No permission to add photos") |
102 |
102 |
|
103 |
manipulator = ImportManipulator() |
|
104 |
if request.POST: |
|
105 |
new_data = request.POST.copy() |
|
106 |
new_data.update(request.FILES) |
|
107 |
errors = manipulator.get_validation_errors(new_data) |
|
108 |
if not errors: |
|
103 |
if request.method == POST: |
|
104 |
form = ImportForm(request.POST, request.FILES) |
|
105 |
if form.is_valid() |
|
109 |
106 |
# So now everything is okay |
110 |
f = StringIO(new_data['zipfile']['content']) # the zip"file" |
|
111 |
zip = zipfile.ZipFile(f) |
|
112 |
manipulator.do_html2python(new_data) |
|
113 |
date = new_data['date'] |
|
107 |
zf = zipfile.ZipFile(request.FILES['zip_file']) |
|
108 |
date = form.cleaned_data['date'] |
|
114 |
109 |
if not date: |
115 |
110 |
date = datetime.date(datetime.now()) |
116 |
111 |
|
| … | … | @@ -119,27 +114,27 @@ def import_photos(request, thegallery): |
119 |
114 |
"%Y/%m/%d/")) |
120 |
115 |
if not os.path.isdir(destdir): |
121 |
116 |
os.makedirs(destdir, 0775) |
122 |
for filename in zip.namelist(): |
|
123 |
photopath = os.path.join(destdir, os.path.basename(filename)) |
|
124 |
data = zip.read(filename) |
|
125 |
file_data = StringIO(data) |
|
126 |
try: |
|
127 |
Image.open(file_data) |
|
128 |
except: |
|
129 |
# don't save and process non Image files |
|
130 |
continue |
|
131 |
photo = file(photopath, "wb") |
|
132 |
photo.write(data) |
|
133 |
||
134 |
# Create the object |
|
135 |
if photopath.startswith(os.path.sep): |
|
136 |
photopath = photopath[len(settings.MEDIA_ROOT):] |
|
137 |
photo = Photo(image=photopath, date=date, |
|
138 |
photographer=new_data['photographer'], |
|
139 |
title = os.path.basename(filename), |
|
140 |
gallery_id = thegallery) |
|
141 |
# Save it -- the thumbnails etc. get created. |
|
142 |
|
|
117 |
for filename in zf.namelist(): |
|
118 |
photopath = os.path.join(destdir, os.path.basename(filename)) |
|
119 |
data = zf.read(filename) |
|
120 |
file_data = StringIO(data) |
|
121 |
try: |
|
122 |
Image.open(file_data) |
|
123 |
except: |
|
124 |
# don't save and process non Image files |
|
125 |
continue |
|
126 |
photo = file(photopath, "wb") |
|
127 |
photo.write(data) |
|
128 |
||
129 |
# Create the object |
|
130 |
if photopath.startswith(os.path.sep): |
|
131 |
photopath = photopath[len(settings.MEDIA_ROOT):] |
|
132 |
photo = Photo(image=photopath, date=date, |
|
133 |
photographer=new_data['photographer'], |
|
134 |
title = os.path.basename(filename), |
|
135 |
gallery_id = thegallery) |
|
136 |
# Save it -- the thumbnails etc. get created. |
|
137 |
photo.save() |
|
143 |
138 |
|
144 |
139 |
# And jump to the directory for this gallery |
145 |
140 |
response = http.HttpResponseRedirect(gallery.get_absolute_url()) |
| … | … | @@ -147,15 +142,12 @@ def import_photos(request, thegallery): |
147 |
142 |
response['Cache-Control'] = 'no-cache' |
148 |
143 |
return response |
149 |
144 |
else: |
150 |
errors = new_data = {} |
|
151 |
form = forms.FormWrapper(manipulator, new_data, errors) |
|
152 |
|
|
145 |
form = ImportForm() |
|
146 |
return render_to_response('stockphoto/import_form.html', |
|
153 |
147 |
dict(form=form, gallery=gallery), |
154 |
148 |
context_instance=RequestContext(request)) |
155 |
# request, |
|
156 |
149 |
|
157 |
import_photos = login_required(import_photos) |
|
158 |
||
150 |
@login_required |
|
159 |
151 |
def export(request, thegallery): |
160 |
152 |
"""Export a gallery to a zip file and send it to the user. |
161 |
153 |
""" |
| … | … | @@ -182,6 +174,4 @@ def export(request, thegallery): |
182 |
174 |
response['Content-Length'] = str(os.stat(outfile.name)[stat.ST_SIZE]) |
183 |
175 |
response['Content-Disposition'] = "attachment; filename=photos.zip" |
184 |
176 |
return response |
185 |
||
186 |
177 |
|
187 |
export = login_required(export) |
