2016-01-01 13 views
5

W celu opracowania niestandardowych pól modelu Django, czytam dokumentację.Jaki jest cel funkcji "dekonstrukcji" modelu Django?

już opracowany moje pole niestandardowe (co jest prawie równa, na przykład: HandField polu odwzorowanym na klasę Pythona ... Z tą tylko różnicą, że dziedziczą z models.CharField i nie models.Field).

from external_library import ExternalClass 

class ExternalClassField(models.CharField): 
    description = "An ExternalClass field" 

    def __init__(self, *args, **kwargs): 
     kwargs['max_length'] = 14 
     super(ExternalClassField, self).__init__(*args, **kwargs) 

    def from_db_value(self, value, expression, connection, context): 
     if value is None: 
      return value 
     return ExternalClass(value) 

    def to_python(self, value): 
     if isinstance(value, ExternalClass): 
      return value 

     if value is None: 
      return value 

     return ExternalClass(value) 

    def get_prep_value(self, value): 
     if value is None: 
      return value 

     if isinstance(value, ExternalClass): 
      return value.to_string() 

     return value 

Pole zachowuje się zgodnie z oczekiwaniami. Jednak utknąłem w tej części dokumentacji: funkcja deconstruct().

W szczególności, co nie rozumiem to:

  • Czym dokładnie jest cel funkcji dekonstrukcji?
  • Dlaczego moje pole działa doskonale nawet bez niego (i nawet jeśli zmienię argumenty init)?
  • Jak i kiedy Django wywołuje funkcję dekonstrukcji?

Nie chcę ślepo kopiować i wklejać kodu, którego nie rozumiem, ale dokumentacja nie jest jasna.

+0

Jest używany w migracji do serializacji pola. – knbk

Odpowiedz

12

Metoda deconstruct() służy do wykonywania migracji modeli, które nie mogą być automatycznie obsługiwane przez system. Przejdźmy przez scenariusz, w którym zostanie wywołana dekonstrukcja.

Załóżmy, że mamy jakiś model i dodaliśmy do niego pole niestandardowe. Próbujemy przeprowadzić migrację za pomocą python manage.py makemigrations.

Spotykamy się następujący błąd:

ValueError: Cannot serialize: Foo 
There are some values Django cannot serialize into migration files. 

Okazuje się, że nie ma już a related ticket, który został złożony w Django Projektu, niech to sprawdzić.

ticket-issue

Jednym z głównych twórców odpowiedział, że to ma problem, ponieważ nasze pole zawiera wywoływalnym.

ticket-resolution

Tak, brakowało nam czegoś w dokumentacji. Istnieje przechowywana wartość do wywołania i nie można jej automatycznie przenieść z jakiegoś powodu. Co możemy zrobić?

Cóż, oprócz opowiadając nam o ValueError, manage.py dał nam także użyteczną link do dokumentacji:

docs-link

Raz na tej stronie, przewiń w dół trochę, aż dojdziemy do sekcja o numerze: serializing values.

Django can serialize the following:

  • ...
  • Anything with a custom deconstruct() method (see below)
  • ...

Cóż, see below:

You can let Django serialize your own custom class instances by giving the class a deconstruct() method. It takes no arguments, and should return a tuple of three things (path, args, kwargs):

  • path should be the Python path to the class, with the class name included as the last part (for example, myapp.custom_things.MyClass). If your class is not available at the top level of a module it is not serializable.
  • args should be a list of positional arguments to pass to your class’ init method. Everything in this list should itself be serializable.
  • kwargs should be a dict of keyword arguments to pass to your class’ init method. Every value should itself be serializable.

Zauważ, że Deconstruct metoda() działa w parze z __eq__(), jak podano w dokumentacji:

To prevent a new migration from being created each time makemigrations is run, you should also add a __eq__() method to the decorated class. This function will be called by Django’s migration framework to detect changes between states.

W moim przypadku, błędem było dodanie nawiasów po wartości, która nie powinna była zostać wywołana, ale w wielu przypadkach będziesz chciał zaimplementować tę metodę dekonstrukcji dla migracji. (Oto inny przykład: useful link, który ma przykład.)

+0

Chciałbym, żeby było więcej takich odpowiedzi na SO! – Nevertheless

+1

Z jakiegoś powodu nie przyjąłem odpowiedzi. Naprawdę przepraszam za to: odpowiedź zaakceptowana. Naprawdę wnikliwe i przydatne, dzięki! – Saturnix