2011-11-30 25 views
62

Tengo un archivo existente en el disco (digamos /folder/file.txt) y un campo de modelo FileField en Django.Establezca FileField de Django en un archivo existente

Cuando hago

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

se re-guarda el archivo como file_1.txt (la próxima vez que es _2, etc.).

Entiendo por qué, pero no quiero este comportamiento - Sé que el archivo con el que quiero que esté asociado el campo realmente está esperándome, y solo quiero que Django lo señale.

¿Cómo?

+1

seguro de que puedes conseguir lo que quieres sin modificar Django o la subclasificación 'FileField'. Siempre que se guarda un 'FileField', se crea una nueva copia del archivo. Sería bastante sencillo agregar una opción para evitar esto. –

+0

Bueno, sí, parece que tengo que crear una subclase y agregar un param. No deseo crear tablas adicionales para esta simple tarea – Guard

+0

Coloque el archivo en una ubicación diferente, cree su campo con esta ruta, guárdelo y luego tendrá el archivo en el destino de upload_to. – benjaoming

Respuesta

18

Si usted quiere hacer esto de forma permanente, lo que necesita para crear su propio Clase 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 

Ahora en su modelo, utiliza su MyFileStorage modificado

from mystuff.customs import MyFileStorage 

mfs = MyFileStorage() 

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

oh, parece prometedor. Porque el código de FileField es un poco no intuitivo – Guard

+0

pero ... ¿es posible cambiar el almacenamiento por solicitud, como: instance.field.storage = mfs; instance.field.save (nombre, archivo); pero no lo hago en una rama diferente de mi código – Guard

+2

No, ya que el motor de almacenamiento está vinculado al modelo. Puede evitar todo esto simplemente almacenando su ruta de archivo en un 'FilePathField' o simplemente como texto sin formato. –

0

¡Tenía exactamente el mismo problema! entonces me doy cuenta de que mis Modelos estaban causando eso. ejemplo que hade mis modelos como esto:

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

Entonces, yo quería tener más el azulejo referencia al mismo archivo en el disco! La manera que he encontrado para resolver ese era cambiar la estructura de mi modelo a esto:

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

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

que, después me di cuenta de que tienen más sentido, porque si yo quiero lo mismo archivo que se guarda más de una en mi DB tengo que crea otra mesa para eso!

Supongo que puede resolver su problema así también, ¡solo esperando que pueda cambiar los modelos!

EDITAR

También supongo que se puede utilizar un almacenamiento diferente, así por ejemplo: SymlinkOrCopyStorage

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

+0

tiene sentido en su caso, no en el mío. No quiero que se haga referencia a esto varias veces. Creo un objeto haciendo referencia a un archivo, luego me doy cuenta de que hay errores en otros atributos y vuelvo a abrir el formulario de creación. En su reenvío, no quiero perder el archivo que ya está guardado en el disco – Guard

+0

, así que supongo que puede usar mi enfoque. ¡porque tendrás una tabla FormFile que contendrá el archivo solo entonces! ¡entonces en tu tabla de formularios tendrás un FK para ese archivo! ¡así que puedes cambiar/crear nuevos formularios para el mismo archivo! (Por cierto, estoy cambiando el orden de FK en mi ejemplo principal) –

+0

¡Si desea publicar su dominio (modelos) en su publicación! ¡También puedo tener una mejor ideia! –

4

Es correcto escribir la clase de almacenamiento propia. Sin embargo, get_available_name no es el método correcto para anular.

get_available_name se llama cuando Django ve un archivo con el mismo nombre e intenta obtener un nuevo nombre de archivo disponible. No es el método el que causa el cambio de nombre. el método causado es _save. Los comentarios en _save son bastante buenos y puede encontrar fácilmente que abre el archivo para escribir con el indicador os.O_EXCL que lanzará un OSError si ya existe el mismo nombre de archivo. Django detecta este error y luego llama al get_available_name para obtener un nuevo nombre.

Así que creo que la forma correcta es anular _save y llamar a os.open() sin marcar os.O_EXCL. La modificación es bastante simple, sin embargo, el método es un poco largo, así que no lo pego aquí.Dime si necesita más ayuda :)

+0

son 50 líneas de código que debe copiar, lo cual es bastante malo. La anulación de get_available_name parece más aislada, más corta y mucho más segura para, por ejemplo, actualizar a las versiones más recientes de Django en el futuro –

+1

El problema de * solo * anular 'get_available_name' es cuando carga un archivo con el mismo nombre, el servidor entrar en un ciclo sin fin. Dado que '_save' verifica el nombre del archivo y decide obtener uno nuevo,' get_available_name' todavía devuelve el nombre duplicado. Entonces debes anular ambos. – x1a0

+1

Vaya, estamos teniendo esta discusión en dos preguntas, pero solo ahora noté que son ligeramente diferentes) Así que estoy en lo cierto en esa pregunta, y usted está en esto) –

83

apenas se fija instance.field.name a la ruta de su archivo

por ejemplo,

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

La ruta relativa de su 'MEDIA_ROOT', que es. – mgalgs

+6

En este ejemplo, creo que también puedes hacer 'doc.file = 'path/to/file'' –

7

probar esto (doc):

instance.field.name = <PATH RELATIVE TO MEDIA_ROOT> 
instance.save() 
No
Cuestiones relacionadas