2009-04-17 20 views
10

Mogę łatwo wypełnić pole FileField lub ImageField w urządzeniu Django z nazwą pliku, ale ten plik nie istnieje i kiedy próbuję przetestować moją aplikację, to się nie uda, ponieważ ten plik nie istnieje.Jak umieścić plik w urządzeniu w Django?

Jak poprawnie wypełnić pole FileField lub Imagefield w urządzeniu Django, aby sam plik był dostępny?

Odpowiedz

7

Obawiam się, że krótka odpowiedź brzmi, że nie można tego zrobić przy użyciu klas FileField lub ImageField; po prostu przechowują ścieżkę pliku i nie mają rzeczywistej koncepcji rzeczywistych danych pliku. Jednak długą odpowiedzią jest to, że wszystko jest możliwe, jeśli korzystasz z interfejsu API Django do pisania własnych custom model fields.

Co najmniej, chcesz zaimplementować metodę value_to_string do konwersji danych do serializacji (jest taki przykład w dokumentach django pod powyższym linkiem). Zauważ, że przykłady na powyższym linku URL zawierają również wzmiankę o podklasach FileField i ImageField, co jest pomocne w twojej sytuacji!

Będziesz także musiał zdecydować, czy dane powinny być przechowywane w bazie danych, czy w systemie plików. W pierwszym przypadku będziesz musiał zaimplementować swoją klasę niestandardową jako pole Blob, w tym personalizację dla każdego DB, który chcesz obsługiwać; będziesz musiał również zapewnić wsparcie dla sposobu, w jaki dane powinny zostać zwrócone użytkownikowi z bazy danych, gdy HTML zażąda adresu URL .gif/.jpg/.png/.whatever. Jeśli to drugie, co jest mądrzejszym sposobem na przejście do IMHO, będziesz musiał wdrożyć metody serializacji, odserializowania danych binarnych do systemu plików. Tak czy inaczej, jeśli zaimplementujesz je jako podklasy FileField i ImageField, nadal będziesz mógł korzystać z narzędzi administracyjnych i innych modułów, które oczekują takich funkcji django.

Jeśli i tylko jeśli zdecydujesz się użyć bardziej zaangażowanego podejścia blob, oto fragment kodu ze starego projektu umysłu (z powrotem, gdy uczyłem się Django), który obsługuje blob dla MySQL i PostgreSQL; prawdopodobnie będziesz w stanie znaleźć wiele ulepszeń, ponieważ nie dotknąłem go od tego czasu :-) Nie zajmuje się serializacją, więc musisz to dodać, używając powyższej metody.

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

Czy chcesz przetestować aplikację korzystającą z FielField I, aby utworzyć inny typ pola i zamienić go? – Pablo

+0

Nie ... Czytam twoje pytanie w ten sposób, że chciałeś, aby urządzenia zawierały dane. Jeśli tylko testujesz działanie FileField i ImageField, po prostu sprawdź, czy generują poprawne adresy URL i ścieżki ... nie martw się o rzeczywiste dane obrazu. –

+0

Nie testuję FileField i ImageField. Testuję stronę, która ich używa, a jedną z rzeczy, którą robią witryny, jest przycinanie obrazów i generowanie miniatur. Jeśli nie ma plików, ten kod nie działa. I nawet jeśli obejdę to, nie testowałbym całkowicie mojej witryny. – Pablo

6

Nie ma sposobu na "uwzględnienie" plików w serializowanym urządzeniu. Tworząc urządzenie testowe, wystarczy zrobić to samemu; upewnij się, że niektóre pliki testowe faktycznie istnieją w lokalizacjach, do których odwołują się wartości FileField/ImageField. Wartości tych pól są ścieżkami w stosunku do MEDIA_ROOT: jeśli musisz, możesz ustawić MEDIA_ROOT w swojej setup() metodzie testowej w niestandardowej konfiguracji test_settings.py, aby upewnić się, że Twoje pliki testowe zostaną znalezione w dowolnym miejscu.

EDIT: Jeśli chcesz to zrobić w konfiguracji() metoda, można również monkeypatch default_storage bezpośrednio:

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 

To wydaje się działać. default_storage to a documented public API, więc powinno to być niezawodne.

+0

Ustawienie MEDIA_ROOT w setUp() brzmi jak bardzo dobry pomysł. Dam temu szansę. Dzięki. – Pablo

+0

Dałem to rozwiązanie, próbując i zmieniając ustawienia.MEDIA_ROOT w metodzie testowej lub metoda setUp nie zmienia się w miejscu, w którym próbuje się znaleźć plik. To rozwiązanie może działać, ale MEDIA_ROOT powinno być zdefiniowane gdzie indziej. – Pablo

+1

Masz rację, przepraszam za to. settings.MEDIA_ROOT jest odczytywany w czasie uruchamiania przez pojedynczą współużytkowaną instancję FileSystemStorage, która jest używana przez wszystkie FileFields. Musiałbyś ustawić go w niestandardowej konfiguracji test_settings.py. –