2009-04-17 9 views
10

Posso facilmente riempire il campo di un FileField o ImageField in un dispositivo Django con un nome di file, ma quel file non esiste e quando provo a testare la mia applicazione fallisce perché quel file non esiste.Come si inserisce un file in un dispositivo in Django?

Come compilare correttamente un FileField o Imagefield in un dispositivo Django in modo che anche il file stesso sia disponibile?

risposta

7

Purtroppo la risposta breve è che non è possibile farlo utilizzando le classi FileField o ImageField; memorizzano semplicemente un percorso di file e non hanno alcun concetto reale dei dati reali del file. La lunga risposta, tuttavia, è che tutto è possibile se sfrutti l'API di Django per scrivere il tuo custom model fields.

Come minimo, è necessario implementare il metodo value_to_string per convertire i dati per la serializzazione (c'è un esempio nei documenti django al link sopra). Nota che gli esempi al link URL sopra includono anche la menzione di sottoclassi FileField e ImageField, che è utile per la tua situazione!

Inoltre, è necessario decidere se i dati devono essere memorizzati nel database o nel file system. Se il primo, dovrai implementare la tua classe personalizzata come un campo Blob, inclusa la personalizzazione per ogni DB che desideri supportare; Dovrai anche fornire un supporto per come i dati devono essere restituiti all'utente fuori dal database quando l'HTML richiede un URL .gif/.jpg/.png/.whatever. Se quest'ultimo, che è il modo più intelligente di implementare IMHO, sarà necessario implementare metodi per serializzare, deserializzare i dati binari nel filesystem. In entrambi i casi, se li implementate come sottoclassi di FileField e ImageField, dovresti comunque essere in grado di utilizzare gli strumenti di amministrazione e altri moduli che prevedono tali funzionalità di django.

Se e solo se si sceglie di utilizzare l'approccio blob più coinvolto, ecco un frammento di codice da un vecchio progetto di mente (indietro quando stavo imparando Django) che gestisce BLOB per MySQL e PostgreSQL; probabilmente non sarai in grado di trovare una serie di miglioramenti in quanto non l'ho toccato dal momento che :-) Non gestisce la serializzazione, quindi dovrai aggiungerla utilizzando il metodo sopra riportato.

from django.db import models 
from django.conf import settings 

class BlobValueWrapper(object): 
    """Wrap the blob value so that we can override the unicode method. 
    After the query succeeds, Django attempts to record the last query 
    executed, and at that point it attempts to force the query string 
    to unicode. This does not work for binary data and generates an 
    uncaught exception. 
    """ 
    def __init__(self, val): 
     self.val = val 

    def __str__(self): 
     return 'blobdata' 

    def __unicode__(self): 
     return u'blobdata' 


class BlobField(models.Field): 
    """A field for persisting binary data in databases that we support.""" 
    __metaclass__ = models.SubfieldBase 

    def db_type(self): 
     if settings.DATABASE_ENGINE == 'mysql': 
      return 'LONGBLOB' 
     elif settings.DATABASE_ENGINE == 'postgresql_psycopg2': 
      return 'bytea' 
     else: 
      raise NotImplementedError 

    def to_python(self, value): 
     if settings.DATABASE_ENGINE == 'postgresql_psycopg2': 
      if value is None: 
       return value 
      return str(value) 
     else: 
      return value 

    def get_db_prep_save(self, value): 
     if value is None: 
      return None 
     if settings.DATABASE_ENGINE =='postgresql_psycopg2': 
      return psycopg2.Binary(value) 
     else: 
      return BlobValueWrapper(value) 
+0

Vuoi dire che per testare un'applicazione che usa FielField dovrei creare un altro tipo di campo e sostituirlo? – Pablo

+0

No ... Ho letto la tua domanda nel senso che volevi che i proiettori includessero i dati. Se stai solo testando che FileField e ImageField funzionano, prova solo che generano gli URL e i percorsi corretti ... non preoccuparti dei dati effettivi delle immagini. –

+0

Non sto testando FileField e ImageField. Sto testando un sito che li usa, e una cosa che fanno i siti è ritagliare le immagini e generare miniature. Se i file non sono lì, quel codice fallisce. E anche se lo risolvo, non testerò completamente il mio sito. – Pablo

6

Non c'è modo di "includere" i file nel dispositivo serializzato. Se si crea un dispositivo di prova, è sufficiente farlo da soli; assicurati che alcuni file di test siano effettivamente presenti nelle posizioni a cui fanno riferimento i valori FileField/ImageField. I valori di questi campi sono percorsi relativi a MEDIA_ROOT: se necessario, è possibile impostare MEDIA_ROOT nel metodo setUp() di prova in un test_settings.py personalizzato per garantire che i file di test vengano trovati ovunque vengano inseriti.

EDIT: Se si desidera farlo nel vostro setup() metodo, è possibile anche monkeypatch default_storage direttamente:

from django.core.files.storage import default_storage 

class MyTest(TestCase): 

    def setUp(self): 
    self._old_default_storage_location = default_storage.location 
    default_storage.location = '/some/other/place' 

    def tearDown(self): 
    default_storage.location = self._old_default_storage_location 

che sembra funzionare. default_storage è a documented public API, quindi questo dovrebbe essere affidabile.

+0

L'impostazione di MEDIA_ROOT in setUp() sembra un'ottima idea. Lo proverò. Grazie. – Pablo

+0

Ho dato a questa soluzione un tentativo e la modifica delle impostazioni.MEDIA_ROOT mentre sul metodo di test o il metodo setUp non cambia dove il file sta cercando di essere localizzato. Questa soluzione potrebbe funzionare, ma MEDIA_ROOT dovrebbe essere definito da qualche altra parte. – Pablo

+1

Hai ragione, mi dispiace per quello. settings.MEDIA_ROOT viene letto all'avvio da una singola istanza condivisa di FileSystemStorage utilizzata da tutti i FileField. Dovresti impostarlo in un test personalizzato_settings.py. –

Problemi correlati