Программное сохранение изображения в Django ImageField
хорошо, я пробовал почти все, и я не могу заставить это работать.
- у меня есть модель Django с ImageField на нем
- у меня есть код, который загружает изображение через HTTP (проверено и работает)
- изображение сохраняется непосредственно в папку 'upload_to' (upload_to-это тот, который установлен на поле ImageField)
- все, что мне нужно сделать, это связать уже существующий путь к файлу изображения с ImageField
у меня есть написан этот код примерно 6 разными способами.
проблема я бегу в это весь код, который я пишу, приводит к следующему поведению:
(1) Django сделает 2-й файл, (2) переименует новый файл, добавив _ в конец имени файла, а затем (3) не передает никаких данных, оставляя его в основном пустым переименованным файлом. То, что осталось в пути 'upload_to' - это 2 файла, один из которых является фактическим изображением, а другой-именем изображения, но пуст, и, конечно же, Путь ImageField устанавливается в пустой файл, который пытается создать Django.
в случае, если это было неясно, я попытаюсь проиллюстрировать:
## Image generation code runs....
/Upload
generated_image.jpg 4kb
## Attempt to set the ImageField path...
/Upload
generated_image.jpg 4kb
generated_image_.jpg 0kb
ImageField.Path = /Upload/generated_image_.jpg
как я могу это сделать без того, чтобы Django попытался повторно сохранить файл? Что мне действительно хотелось бы, так это что-то в этом роде...
model.ImageField.path = generated_image_path
...но, конечно, это не работает.
и да, я прошел через другие вопросы здесь, как этот, а также Django doc on File
обновление
После дальнейшего тестирования он выполняет это поведение только при работе под управлением Apache на Windows Server. Во время работы под "runserver" на XP он не выполняет это поведение.
Я в тупик.
вот код, который успешно работает на XP...
f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()
14 ответов:
у меня есть код, который извлекает изображение из интернета и сохраняет его в модели. Важными битами являются:
from django.core.files import File # you need this somewhere import urllib # The following actually resides in a method of my model result = urllib.urlretrieve(image_url) # image_url is a URL to an image # self.photo is the ImageField self.photo.save( os.path.basename(self.url), File(open(result[0], 'rb')) ) self.save()Это немного запутанно, потому что он вытащил из моей модели и немного из контекста, но важные части:
- изображение, извлеченное из интернета,не хранится в папке upload_to, вместо этого он хранится в виде tempfile по urllib.urlretrieve (), а потом отказались.
- В ImageField.метод save () принимает имя файла (ОС.путь.basename bit) и Джанго.ядро.файлы.Объект file.
Дайте мне знать, если у вас есть вопросы или нуждаются в уточнении.
Edit: для ясности, вот модель (минус любые необходимые операторы импорта):
class CachedImage(models.Model): url = models.CharField(max_length=255, unique=True) photo = models.ImageField(upload_to=photo_path, blank=True) def cache(self): """Store image locally if we have a URL""" if self.url and not self.photo: result = urllib.urlretrieve(self.url) self.photo.save( os.path.basename(self.url), File(open(result[0], 'rb')) ) self.save()
супер легко, если модель еще не создана:
первый, скопируйте файл изображения в путь загрузки (предполагается = 'путь/' в следующем фрагменте).
второй, например:
class Layout(models.Model): image = models.ImageField('img', upload_to='path/') layout = Layout() layout.image = "path/image.png" layout.save()протестировано и работает в django 1.4, он может работать также для существующей модели.
просто небольшое замечание. tvon ответ работает, но, если вы работаете на windows, вы, вероятно, хотите
open()файл'rb'. Вот так:class CachedImage(models.Model): url = models.CharField(max_length=255, unique=True) photo = models.ImageField(upload_to=photo_path, blank=True) def cache(self): """Store image locally if we have a URL""" if self.url and not self.photo: result = urllib.urlretrieve(self.url) self.photo.save( os.path.basename(self.url), File(open(result[0], 'rb')) ) self.save()или вы получите ваш файл обрезается до первого
0x1Aбайт.
вот метод, который хорошо работает и позволяет конвертировать файл в определенный формат, а также (чтобы избежать" не удается записать режим P как JPEG " ошибка):
import urllib2 from django.core.files.base import ContentFile from PIL import Image from StringIO import StringIO def download_image(name, image, url): input_file = StringIO(urllib2.urlopen(url).read()) output_file = StringIO() img = Image.open(input_file) if img.mode != "RGB": img = img.convert("RGB") img.save(output_file, "JPEG") image.save(name+".jpg", ContentFile(output_file.getvalue()), save=False)где изображение-это поле django ImageField или your_model_instance.изображение вот пример использования:
p = ProfilePhoto(user=user) download_image(str(user.id), p.image, image_url) p.save()надеюсь, что это помогает
ок, если все, что вам нужно сделать, это связать уже существующий путь к файлу изображения с ImageField, то это решение может быть полезно:
from django.core.files.base import ContentFile with open('/path/to/already/existing/file') as f: data = f.read() # obj.image is the ImageField obj.image.save('imgfilename.jpg', ContentFile(data))Ну, если серьезно, то уже существующий файл изображения не будет связан с ImageField, но копия этого файла будет создана в upload_to dir как 'imgfilename.jpg ' и будет связан с полем изображения.
то, что я сделал, это создать свое собственное хранилище, которое просто не будет сохранять файл на диск:
from django.core.files.storage import FileSystemStorage class CustomStorage(FileSystemStorage): def _open(self, name, mode='rb'): return File(open(self.path(name), mode)) def _save(self, name, content): # here, you should implement how the file is to be saved # like on other machines or something, and return the name of the file. # In our case, we just return the name, and disable any kind of save return name def get_available_name(self, name): return nameзатем, в моих моделях, для моего ImageField, я использовал новое пользовательское хранилище:
from custom_storage import CustomStorage custom_store = CustomStorage() class Image(models.Model): thumb = models.ImageField(storage=custom_store, upload_to='/some/path')
Если вы хотите просто "установить" фактическое имя файла, не неся накладные расходы на загрузку и повторное сохранение файла (!!), или прибегая к использованию страничке (!!!), вы можете попробовать что-то вроде этого --
model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')это осветит ваш model_instance.мой файл.URL и все остальные, как если бы вы на самом деле загрузили файл.
как @t-stone говорит, что мы действительно хотим, чтобы иметь возможность установить экземпляр.мой файл.path = ' my-filename.jpg', но Django в настоящее время не поддерживает это.
простое решение на мой взгляд:
from django.core.files import File with open('path_to_file', 'r') as f: # use 'rb' mode for python3 data = File(f) model.image.save('filename', data, True)
Это может быть не тот ответ, который вы ищете. но вы можете использовать charfield для хранения пути к файлу вместо ImageFile. Таким образом, вы можете программно связать загруженное изображение с полем без повторного создания файла.
class tweet_photos(models.Model): upload_path='absolute path' image=models.ImageField(upload_to=upload_path) image_url = models.URLField(null=True, blank=True) def save(self, *args, **kwargs): if self.image_url: import urllib, os from urlparse import urlparse file_save_dir = self.upload_path filename = urlparse(self.image_url).path.split('/')[-1] urllib.urlretrieve(self.image_url, os.path.join(file_save_dir, filename)) self.image = os.path.join(file_save_dir, filename) self.image_url = '' super(tweet_photos, self).save()
class Pin(models.Model): """Pin Class""" image_link = models.CharField(max_length=255, null=True, blank=True) image = models.ImageField(upload_to='images/', blank=True) title = models.CharField(max_length=255, null=True, blank=True) source_name = models.CharField(max_length=255, null=True, blank=True) source_link = models.CharField(max_length=255, null=True, blank=True) description = models.TextField(null=True, blank=True) tags = models.ForeignKey(Tag, blank=True, null=True) def __unicode__(self): """Unicode class.""" return unicode(self.image_link) def save(self, *args, **kwargs): """Store image locally if we have a URL""" if self.image_link and not self.image: result = urllib.urlretrieve(self.image_link) self.image.save(os.path.basename(self.image_link), File(open(result[0], 'r'))) self.save() super(Pin, self).save()
вы можете использовать Django REST framework и python запросы библиотека для программного сохранения изображения в Django ImageField
вот пример:
import requests def upload_image(): # PATH TO DJANGO REST API url = "http://127.0.0.1:8080/api/gallery/" # MODEL FIELDS DATA data = {'first_name': "Rajiv", 'last_name': "Sharma"} # UPLOAD FILES THROUGH REST API photo = open('/path/to/photo'), 'rb') resume = open('/path/to/resume'), 'rb') files = {'photo': photo, 'resume': resume} request = requests.post(url, data=data, files=files) print(request.status_code, request.reason)
работает! Вы можете сохранить изображение с помощью FileSystemStorage. проверьте пример ниже
def upload_pic(request): if request.method == 'POST' and request.FILES['photo']: photo = request.FILES['photo'] name = request.FILES['photo'].name fs = FileSystemStorage() ##### you can update file saving location too by adding line below ##### fs.base_location = fs.base_location+'/company_coverphotos' ################## filename = fs.save(name, photo) uploaded_file_url = fs.url(filename)+'/company_coverphotos' Profile.objects.filter(user=request.user).update(photo=photo)
Comments