2011-11-30 24 views
62

Tôi có tệp hiện có trên đĩa (nói /folder/file.txt) và trường mô hình FileField ở Django.Đặt FileField của Django thành một tệp hiện có

Khi tôi làm

instance.field = File(file('/folder/file.txt')) 
instance.save() 

nó lại tiết kiệm nội dung tập tin file_1.txt (thời gian tiếp theo đó là _2, vv).

Tôi hiểu tại sao, nhưng tôi không muốn hành vi này - tôi biết tập tin tôi muốn trường được liên kết với thực sự là có chờ đợi cho tôi, và tôi chỉ muốn Django để trỏ đến nó.

Làm cách nào?

+1

Không chắc bạn có thể có được những gì bạn muốn mà không sửa đổi Django hoặc subclassing 'FileField'. Bất cứ khi nào một 'FileField' được lưu, một bản sao mới của tập tin được tạo ra. Nó sẽ khá đơn giản để thêm một tùy chọn để tránh điều này. –

+0

vâng, có vẻ như tôi phải phân lớp và thêm thông số. Tôi không muốn tạo thêm các bảng cho nhiệm vụ đơn giản này – Guard

+0

Đặt tệp ở một vị trí khác, tạo trường của bạn với đường dẫn này, lưu nó và sau đó bạn có tệp trong đích tải lên. – benjaoming

Trả lời

18

Nếu bạn muốn làm điều này vĩnh viễn, bạn cần tạo riêng của bạn Lớp FileStorage

from django.core.files.storage import FileSystemStorage 

class MyFileStorage(FileSystemStorage): 

    # This method is actually defined in Storage 
    def get_available_name(self, name): 
     return name # simply returns the name passed 

Bây giờ trong mô hình của bạn, bạn sử dụng MyFileStorage đã sửa đổi của bạn

from mystuff.customs import MyFileStorage 

mfs = MyFileStorage() 

class SomeModel(model.Model): 
    my_file = model.FileField(storage=mfs) 
+0

oh, có vẻ đầy hứa hẹn. cuase mã FileField là kinda không trực quan – Guard

+0

nhưng ... là nó có thể thay đổi lưu trữ trên cơ sở cho mỗi yêu cầu, như: instance.field.storage = mfs; instance.field.save (tên, tệp); nhưng không thực hiện nó trong một nhánh khác của mã của tôi – Guard

+2

Không, vì công cụ lưu trữ được gắn với mô hình. Bạn có thể tránh tất cả điều này bằng cách đơn giản lưu trữ đường dẫn tệp của bạn trong một tệp 'FilePathField' hoặc đơn giản là văn bản thuần túy. –

0

Tôi đã có chính xác cùng một vấn đề! sau đó tôi nhận ra rằng Mô hình của tôi đã gây ra điều đó. ví dụ: Tôi hade mô hình của mình như thế này:

class Tile(models.Model): 
    image = models.ImageField() 

Sau đó, tôi muốn có thêm một ô tham chiếu cùng một tệp trong đĩa! Cách mà tôi tìm thấy để giải quyết đó là thay đổi cấu trúc mô hình của tôi như thế này:

class Tile(models.Model): 
    image = models.ForeignKey(TileImage) 

class TileImage(models.Model): 
    image = models.ImageField() 

nào sau khi tôi nhận ra rằng có ý nghĩa hơn, bởi vì nếu tôi muốn cùng một tập tin được lưu nhiều hơn thì một trong DB của tôi, tôi phải tạo một bảng khác cho nó!

Tôi đoán bạn có thể giải quyết vấn đề của bạn như vậy, chỉ hy vọng rằng bạn có thể thay đổi mô hình!

EDIT

Ngoài ra tôi đoán bạn có thể sử dụng một lưu trữ khác nhau, như thế này ví dụ: SymlinkOrCopyStorage

http://code.welldev.org/django-storages/src/11bef0c2a410/storages/backends/symlinkorcopy.py

+0

có ý nghĩa trong trường hợp của bạn, chứ không phải của tôi. Tôi không muốn nó được tham chiếu nhiều lần. Tôi tạo một đối tượng tham chiếu một tập tin, sau đó tôi nhận ra có lỗi trong các attrs khác, và tôi mở lại các hình thức sáng tạo. Ngày gửi lại của nó tôi không muốn để mất tập tin đó đã được lưu trên đĩa – Guard

+0

vì vậy tôi đoán bạn có thể sử dụng cách tiếp cận của tôi! bởi vì bạn sẽ có một FormFile bảng mà sẽ giữ các tập tin chỉ sau đó bạn có! sau đó trong bảng Form của bạn, bạn sẽ có một FK cho tập tin đó! vì vậy bạn có thể thay đổi/tạo biểu mẫu mới cho cùng một tệp! (btw Tôi đang thay đổi thứ tự của FK trong ví dụ chính của tôi) –

+0

Nếu bạn muốn đăng tên miền (các mô hình) trong bài đăng của mình! tôi cũng có thể có một ý thức tốt hơn! –

4

Có quyền viết lớp lưu trữ riêng. Tuy nhiên get_available_name không phải là phương pháp đúng để ghi đè.

get_available_name được gọi khi Django thấy một tệp có cùng tên và cố gắng lấy tên tệp khả dụng mới. Nó không phải là phương pháp gây ra việc đổi tên. phương pháp gây ra là _save. Bình luận trong _save là khá tốt và bạn có thể dễ dàng tìm thấy nó sẽ mở tập tin để viết với cờ os.O_EXCL mà sẽ ném một OSError nếu cùng một tên tập tin đã tồn tại. Django bắt lỗi này sau đó gọi get_available_name để lấy tên mới.

Vì vậy, tôi nghĩ rằng cách chính xác là ghi đè _save và gọi os.open() mà không có cờ os.O_EXCL. Việc sửa đổi khá đơn giản tuy nhiên phương pháp này hơi dài nên tôi không dán nó ở đây.Nói cho tôi biết nếu bạn cần thêm sự giúp đỡ :)

+0

là 50 dòng mã mà bạn phải sao chép, điều này khá tệ. Overriding get_available_name dường như là cô lập hơn, ngắn hơn và an toàn hơn nhiều, ví dụ, nâng cấp lên phiên bản mới hơn của Django trong tương lai –

+1

Vấn đề của * only * ghi đè 'get_available_name' là khi bạn tải lên một tệp có cùng tên, máy chủ sẽ nhận được vào một vòng lặp vô tận. Vì '_save' kiểm tra tên tệp và quyết định lấy tên tệp mới, tuy nhiên' get_available_name' vẫn trả về tên trùng lặp. Vì vậy, bạn cần phải ghi đè cả hai. – x1a0

+1

Rất tiếc, chúng tôi đang thảo luận trong hai câu hỏi, nhưng chỉ bây giờ tôi nhận thấy rằng chúng hơi khác nhau) Vì vậy, tôi đúng trong câu hỏi đó và bạn đang ở trong này) –

83

chỉ cần đặt instance.field.name đến đường dẫn của tập tin của bạn

ví dụ

class Document(models.Model): 
    file = FileField(upload_to=get_document_path) 
    description = CharField(max_length=100) 


doc = Document() 
doc.file.name = 'path/to/file' # must be relative to MEDIA_ROOT 
doc.file 
<FieldFile: path/to/file> 
+11

Đường dẫn tương đối từ 'MEDIA_ROOT' của bạn, Là. – mgalgs

+6

Trong ví dụ này, tôi nghĩ bạn cũng có thể chỉ cần 'doc.file = 'path/to/file'' –

7

thử này (doc):

instance.field.name = <PATH RELATIVE TO MEDIA_ROOT> 
instance.save() 
Các vấn đề liên quan