2010-07-25 25 views
6
class MyModel(models.Model) 
image = models.FileField(upload_to="blagh blagh...") 
#more spam... 

Tôi có một tập tin trong bộ nhớ và tôi muốn lưu nó qua Django FileField phương pháp tiết kiệm, như thế này:một StringIO như lớp, mà kéo dài django.core.files.File

photo.image.save(name, buffer) # second arg should be django File 

tôi đã cố gắng sử dụng StringIO, nhưng nó không mở rộng django.core.files.File và do đó không thực hiện các khối phương thức(). Tôi đã gói nó trong một đối tượng Tệp như vậy:

buffile = File(buffer, name) # first argument should be a file 
photo.image.save(name, buffile) 

Nhưng phương pháp tệp sử dụng kích thước và tên trường của tệp được cung cấp. StringIO không định nghĩa chúng. Tôi đã tìm thấy this, nhưng liên kết đã chết

Trả lời

7

Nếu bạn đã có một dòng byte, mà bạn muốn lưu vào một FileField/ImageField, đây là một số mã có thể giúp:

>>> from django.core.files.uploadedfile import InMemoryUploadedFile 
>>> from cStringIO import StringIO 
>>> buf = StringIO(data) # `data` is your stream of bytes 
>>> buf.seek(0, 2) # Seek to the end of the stream, so we can get its length with `buf.tell()` 
>>> file = InMemoryUploadedFile(buf, "image", "some_filename.png", None, buf.tell(), None) 
>>> photo.image.save(file.name, file) # `photo` is an instance of `MyModel` 
>>> photo.image 
<ImageFieldFile: ...> 

Một số lưu ý:

  • Bạn có thể tạo bất kỳ tên nào bạn muốn cho hình ảnh nhưng có thể bạn muốn giữ cho tiện ích mở rộng chính xác
  • Đối số thứ hai cho InMemoryUploadedFile là tên của trường trong mô hình của bạn, do đó "hình ảnh"

Đó là một chút khó khăn, nhưng nó được hoàn thành công việc. Hy vọng rằng, API sẽ được làm sạch thêm một chút trong 1.3/4.

Edit:
Xem Jason's answer kiếm một cách đơn giản hơn nhiều để làm điều này, mặc dù bạn vẫn sẽ muốn biết tên tập tin của hình ảnh.

+0

Cảm ơn người đàn ông :) – exshinigami

0

Sử dụng lớp Image.

+0

tôi coi đó, nhưng sau đó tôi sẽ không sử dụng cơ chế django để đặt tên file (nếu một tập tin với một định tên tồn tại, thêm gạch dưới vào tên tệp). Và có, tôi biết, tôi có thể làm điều đó một mình và tôi có thể làm điều đó theo cách khác, nhưng nó sẽ là tốt nhất nếu tôi làm điều đó, như tôi đã mô tả trước đây. – joozek

26

Bạn có thể sử dụng ContentFile thay vì tập tin

from django.core.files.base import ContentFile 

photo.image.save(name, ContentFile(buffer)) 
+3

Gọn gàng! Điều này đơn giản hơn nhiều so với giải pháp của tôi ... + 1 – elo80ka

7

Re Jason của câu trả lời. Lưu ý rằng ContentFile chỉ chấp nhận các chuỗi, không phải bất kỳ đối tượng giống như tệp nào. Dưới đây là một trong đó không -

from django.core.files.base import * 

class StreamFile(ContentFile): 
    """ 
    Django doesn't provide a File wrapper suitable 
    for file-like objects (eg StringIO) 
    """ 
    def __init__(self, stream): 
     super(ContentFile, self).__init__(stream) 
     stream.seek(0, 2) 
     self.size = stream.tell() 

Bây giờ bạn có thể làm những thứ như thế này -

photo.image.save(name, StreamFile(io)) 
+0

Đây là câu trả lời đúng thực tế, đã lưu ngày của tôi! – danigosa

+0

FWIW, ngày nay 'ContentFile' cũng chấp nhận byte. –

Các vấn đề liên quan