2009-04-17 5 views
10

Ich kann problemlos das Feld eines FileField oder ImageField in einem Django Fixture mit einem Dateinamen füllen, aber diese Datei existiert nicht und wenn ich versuche, meine Anwendung zu testen, schlägt es fehl, weil diese Datei nicht existiert.Wie fügst du eine Datei in Django ein?

Wie bearbeite ich ein FileField oder Imagefield in einem Django Fixture korrekt, so dass die Datei selbst auch verfügbar ist?

Antwort

7

Ich fürchte, die kurze Antwort ist, dass Sie dies nicht mit den Klassen FileField oder ImageField tun können; Sie speichern nur einen Dateipfad und haben kein wirkliches Konzept der tatsächlichen Daten der Datei. Die lange Antwort ist jedoch, dass alles möglich ist, wenn Sie die Django API zum Schreiben Ihrer eigenen custom model fields nutzen.

Sie sollten mindestens die Methode value_to_string implementieren, um die Daten für die Serialisierung zu konvertieren (es gibt ein Beispiel in der django-Dokumentation unter dem obigen Link). Beachten Sie, dass die Beispiele im URL-Link oben auch die Erwähnung der Unterklassen FileField und ImageField enthalten, was für Ihre Situation hilfreich ist!

Sie müssen auch entscheiden, ob die Daten daher in der Datenbank oder im Dateisystem gespeichert werden sollen. Im ersten Fall müssen Sie Ihre benutzerdefinierte Klasse als Blob-Feld implementieren, einschließlich der Anpassung für jede Datenbank, die Sie unterstützen möchten. Sie müssen auch einige Unterstützung dafür bereitstellen, wie die Daten an den Benutzer aus der Datenbank zurückgegeben werden sollen, wenn der HTML-Code eine .gif/.jpg/.png/.whatever-URL anfordert. Wenn Letzteres der intelligentere Weg ist, IMHO zu gehen, müssen Sie Methoden zum Serialisieren und Deinserialisieren binärer Daten in das Dateisystem implementieren. In jedem Fall sollten Sie, wenn Sie diese als Unterklassen von FileField und ImageField implementieren, weiterhin die Admin-Tools und andere Module verwenden können, die solche Django-Funktionen erwarten.

Wenn und nur wenn Sie den komplizierteren Blob-Ansatz verwenden, hier ist ein Code-Ausschnitt aus einem alten Projekt des Geistes (zurück, als ich Django lernte), das Blob für MySQL und PostgreSQL behandelt; Sie werden wahrscheinlich eine Reihe von Verbesserungen finden können, da ich sie seither nicht mehr behandelt habe :-) Es funktioniert jedoch nicht mit der Serialisierung, also müssen Sie das mit der obigen Methode hinzufügen.

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

Meinen Sie, dass zum Testen einer Anwendung, die FielField verwendet, ich einen anderen Feldtyp erstellen und ersetzen soll? – Pablo

+0

Nein ... Ich habe Ihre Frage dahingehend gelesen, dass die Geräte die Daten enthalten sollen. Wenn Sie nur testen, ob FileField und ImageField funktionieren, dann testen Sie einfach, ob sie die richtigen URLs und Pfade erzeugen ... machen Sie sich keine Sorgen über die tatsächlichen Bilddaten. –

+0

Ich teste nicht FileField und ImageField. Ich teste eine Website, die sie verwendet, und eine Sache, die die Sites macht, ist das Zuschneiden der Bilder und das Erstellen von Thumbnails. Wenn die Dateien nicht da sind, schlägt der Code fehl. Und selbst wenn ich daran herumarbeiten würde, würde ich meine Seite nicht vollständig testen. – Pablo

6

Es gibt keine Möglichkeit, die Dateien in das serialisierte Gerät "einzuschließen". Wenn Sie ein Testgerät erstellen, müssen Sie es nur selbst tun. Stellen Sie sicher, dass einige Testdateien tatsächlich an Orten vorhanden sind, auf die von den FileField/ImageField-Werten verwiesen wird. Die Werte dieser Felder sind Pfade relativ zu MEDIA_ROOT: Falls erforderlich, können Sie MEDIA_ROOT in Ihrer Test-setUp() -Methode in einem benutzerdefinierten test_settings.py festlegen, um sicherzustellen, dass Ihre Testdateien überall dort gefunden werden, wo Sie sie abgelegt haben.

EDIT: Wenn Sie es in Ihrem Setup() -Methode tun möchten, können Sie auch direkt default_storage monkeypatch:

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 

Das scheint zu funktionieren. default_storage ist , also sollte dies zuverlässig sein.

+0

Das Einstellen von MEDIA_ROOT in setUp() klingt nach einer sehr guten Idee. Ich werde es versuchen. Vielen Dank. – Pablo

+0

Ich habe diese Lösung versucht und Einstellungen ändern.MEDIA_ROOT während der Testmethode oder die Methode setUp ändert nicht, wo die Datei versucht wird, zu finden. Diese Lösung funktioniert möglicherweise, aber MEDIA_ROOT sollte woanders definiert werden. – Pablo

+1

Sie haben Recht, tut mir leid. settings.MEDIA_ROOT wird zur Startzeit von einer einzelnen gemeinsam genutzten Instanz von FileSystemStorage gelesen, die von allen FileFields verwendet wird. Sie müssten es in einem benutzerdefinierten test_settings.py festlegen. –

Verwandte Themen