2009-09-07 10 views
5

Chcę upewnić się, że obiekt jest unikalny i rzucić błąd, gdy użytkownik próbuje go zapisać (np. Przez administratora), jeśli nie? Przez unikatowy, mam na myśli, że niektóre z atrybutów obiektu mogą mieć te same wartości, co inne obiekty, ale nie mogą one być ALL identyczne z wartościami innego obiektu.DRY unikatowe obiekty w Django

Jeśli się nie mylę, mogę to zrobić tak:

class Animal(models.Model): 
    common_name = models.CharField(max_length=150) 
    latin_name = models.CharField(max_length=150) 
    class Meta: 
     unique_together = ("common_name", "latin_name") 

Ale za każdym razem byłaby modelu (np dodać nowe pole, lub zmienić nazwę istniejącego pola), Muszę również edytować listę pól w nawiasach przypisanych do unique_together. Z prostym modelem, to jest w porządku, ale z istotnym, staje się prawdziwym kłopotem podczas refaktoryzacji.

Jak można uniknąć powtarzania pisania listy nazw pól w nawiasach unique_together? Czy jest jakiś sposób przekazania listy pól modelu do zmiennej i zamiast tego przypisać tę zmienną do unique_together?

+1

+1 - wielki pytanie. Nie sądzę, że możesz, ale jestem zainteresowany słuchaniem opinii innych. –

+0

+1 - To naprawdę interesujące, jeśli ktoś znajdzie dobre rozwiązanie. Próbowałem, ale nie mogłem sprawić, by działało to poprzez odbicie, ponieważ nie można odczytać właściwości z klasy Animal (co jest oczywiste, ponieważ Animal nie jest w tym momencie całkowicie zdefiniowany). – FlorianH

+0

jtiai na irc: //irc.freenode.net/django uprzejmie poświęciłem trochę czasu na omówienie pytania i zasugerowałem, żebym mógł "dodać własną klasę" AllUniqueModel ", dziedziczyć standardowy" Model "i zrobić magię metaclass, aby wstrzyknąć wszystkie pola w unique_togerther po przetworzeniu przez standardową procedurę tworzenia. " Nie jestem do końca pewien, co to ma znaczenie dla jtiai, ale brzmi to jak bardziej skomplikowane rozwiązanie, niż miałem nadzieję. – sampablokuper

Odpowiedz

4

modele Refaktoryzacja jest dość drogie rzeczy do zrobienia:

  • Trzeba będzie zmienić cały kod przy użyciu modeli od nazwy pól odpowiadają właściwości obiektów
  • Będziesz musiał ręcznie zmienić swoją bazę od Django nie mogę tego zrobić dla ciebie (przynajmniej wersja, której używał ostatni raz kiedy pracowałem z Django nie mogłem)

Dlatego uważam, że uaktualnienie listy unikalnych nazw pól w klasie meta modelu jest najmniejszym problemem powinienem się martwić atak.

EDIT: Jeśli naprawdę chcesz to zrobić i wszystkie swoich pól musi być „wyjątkowy razem”, to facet w freenode ma rację i trzeba napisać niestandardowy metaklasa. Jest to dość skomplikowane i powoduje błąd, a ponadto może spowodować, że twój kod będzie niekompatybilny z przyszłymi wersjami Django.

"Magia" ORM Django jest kontrolowana przez metaklasę ModelBase (django.db.models.base.ModelBase) ogólnej podstawowej klasy Model. Ta klasa jest odpowiedzialna za przyjęcie definicji twojej klasy z wszystkimi polami i informacjami o Meta i skonstruowanie klasy, której będziesz używać w kodzie później.

Oto przepis na jaki można osiągnąć swój cel:

  1. podklasa ModelBase używać własnego metaklasa.
  2. zastąpić metodę __new__(cls, name, bases, dict)
  3. Sprawdzić dict zebrać człon Meta (dict["Meta"]), jak również wszystkich członków terenowych
  4. Ustaw meta.unique_together na podstawie nazw pól, które zebrali.
  5. połączeń super realizacja (ModelBase.__new__)
  6. Użyj niestandardowych metaklasa dla wszystkich unikalnych modeli wykorzystujących magicznego elementu __metaclass__ = MyMetaclass (lub wyprowadzić abstrakcyjna klasa bazowa rozszerzenie Model i przesłanianie metaklasą)
+1

Na etapie prototypowania modele refaktoryzacji są tanie, ale powielanie kodu jest drogie, stąd moje pytanie. Oczywiście, w produkcji jest to inna kwestia, ale jeśli uda się znaleźć dobrą odpowiedź na moje pytanie, to przynajmniej zmniejszy * jeden * etapów, które musiałbym podjąć podczas refaktoryzacji w produkcji. – sampablokuper

+1

Zobacz moją zaktualizowaną odpowiedź na długą odpowiedź, być może zrozumiesz, że może to być zbyt skomplikowane zadanie. –

+2

Dziękujemy za zaktualizowanie odpowiedzi. Tak, widzę, że osiągnięcie tego jest dość kłopotliwe. Hmm. Byłoby dobrze, gdyby Django mógł po prostu podać opcję ** unikatowego \ _together = (all) ** lub somesuch, lub gdyby mógł pozwolić modelom na samodzielne wykonywanie introspekcji w celu wygenerowania listy pól do przekazania do opcji Meta, itd. . Lub oba :) – sampablokuper