Mam istniejący plik na dysku (powiedzmy /folder/file.txt) i pole modelu FileField w Django.
Kiedy robię
instance.field = File(file('/folder/file.txt'))
instance.save()
ponownie zapisuje plik jako file_1.txt
(następnym razem _2
, itp.).
Rozumiem dlaczego, ale nie chcę tego zachowania - wiem, że plik, z którym ma być skojarzone pole, naprawdę na mnie czeka i chcę tylko, aby Django na niego wskazał.
W jaki sposób?
FileField
. Za każdym razem, gdyFileField
zapisywany jest plik, tworzona jest nowa kopia pliku. Dodanie opcji unikania tego byłoby dość proste.Odpowiedzi:
Jeśli chcesz to zrobić na stałe, musisz utworzyć własną klasę FileStorage
import os from django.conf import settings from django.core.files.storage import FileSystemStorage class MyFileStorage(FileSystemStorage): # This method is actually defined in Storage def get_available_name(self, name): if self.exists(name): os.remove(os.path.join(settings.MEDIA_ROOT, name)) return name # simply returns the name passed
Teraz w swoim modelu używasz zmodyfikowanego MyFileStorage
from mystuff.customs import MyFileStorage mfs = MyFileStorage() class SomeModel(model.Model): my_file = model.FileField(storage=mfs)
źródło
FilePathField
lub po prostu jako zwykły tekst.po prostu ustaw
instance.field.name
ścieżkę do swojego plikuna przykład
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>
źródło
MEDIA_ROOT
znaczy względna ścieżka od twojej .doc.file = 'path/to/file'
spróbuj tego ( dokument ):
źródło
Dobrze jest napisać własną klasę pamięci. Jednak
get_available_name
nie jest to właściwa metoda zastąpienia.get_available_name
jest wywoływana, gdy Django widzi plik o tej samej nazwie i próbuje uzyskać nową dostępną nazwę pliku. To nie metoda powoduje zmianę nazwy. metoda spowodowała to_save
. Komentarze w programie_save
są całkiem dobre i łatwo można znaleźć, że otwiera on plik do zapisu z flagą,os.O_EXCL
która wyrzuci błąd OSError, jeśli plik o tej samej nazwie już istnieje. Django wychwytuje ten błąd, a następnie wywołuje,get_available_name
aby uzyskać nową nazwę.Więc myślę, że poprawnym sposobem jest przesłonięcie
_save
i wywołanie os.open () bez flagios.O_EXCL
. Modyfikacja jest dość prosta, jednak metoda jest trochę za długa, więc nie wklejam jej tutaj. Powiedz mi, czy potrzebujesz więcej pomocy :)źródło
get_available_name
że gdy przesyłasz plik o tej samej nazwie, serwer zapętla się w nieskończoność. Ponieważ_save
sprawdza nazwę pliku i decyduje się na nową, jednakget_available_name
nadal zwraca zduplikowaną. Musisz więc zastąpić oba.Miałem dokładnie ten sam problem! potem zdaję sobie sprawę, że powodowały to moje Modele. przykład Mam moje modele w ten sposób:
class Tile(models.Model): image = models.ImageField()
Następnie chciałem mieć więcej jednego kafelka odwołującego się do tego samego pliku na dysku! Sposób, w jaki znalazłem rozwiązanie, polegał na zmianie struktury mojego modelu na następującą:
class Tile(models.Model): image = models.ForeignKey(TileImage) class TileImage(models.Model): image = models.ImageField()
Co po tym, jak zdaję sobie sprawę, że ma to więcej sensu, ponieważ jeśli chcę, aby ten sam plik był zapisywany więcej niż jeden w mojej bazie danych, muszę utworzyć dla niego kolejną tabelę!
Myślę, że możesz rozwiązać swój problem w ten sposób, mając tylko nadzieję, że możesz zmienić modele!
EDYTOWAĆ
Wydaje mi się, że możesz użyć innego magazynu, na przykład tego: SymlinkOrCopyStorage
http://code.welldev.org/django-storages/src/11bef0c2a410/storages/backends/symlinkorcopy.py
źródło
Należy zdefiniować własny magazyn, odziedziczyć go z FileSystemStorage i nadpisać
OS_OPEN_FLAGS
atrybut iget_available_name()
metodę klasy :Wersja Django: 3.1.0
Projekt / core / files / storages / backends / local.py
import os from django.core.files.storage import FileSystemStorage class OverwriteStorage(FileSystemStorage): """ FileSystemStorage subclass that allows overwrite the already existing files. Be careful using this class, as user-uploaded files will overwrite already existing files. """ # The combination that don't makes os.open() raise OSError if the # file already exists before it's opened. OS_OPEN_FLAGS = os.O_WRONLY | os.O_TRUNC | os.O_CREAT | getattr(os, 'O_BINARY', 0) def get_available_name(self, name, max_length=None): """ This method will be called before starting the save process. """ return name
W swoim modelu użyj niestandardowego OverwriteStorage
myapp / models.py
from django.db import models from core.files.storages.backends.local import OverwriteStorage class MyModel(models.Model): my_file = models.FileField(storage=OverwriteStorage())
źródło