2010-10-05 12 views
7

Korzystanie poniższy kod:Błąd przy użyciu pola klasy bazowej w podklasie unique_together opcji meta

class Organization(models.Model): 
    name = models.CharField(max_length="100",) 
    alias = models.SlugField() 
    ... 

class Division(Organization): 
    parent_org = models.ForeignKey(Organization) 

    class Meta: 
     unique_together=['parent_org', 'alias'] 
     ... 

Próbując syncdb dać mi ten błąd:

Error: One or more models did not validate: 
organizations.division: "unique_together" refers to alias. This is not in the 
same model as the unique_together statement. 

Każda pomoc jest mile widziana,

Dziękujemy,

Eric

+0

można wyjaśnić wymóg więcej, nie są w stanie zrozumieć, co potrzeba, aby odziedziczyć Organizacja i mający ForeignKey do tego samego modelu bazowego. –

+0

Jest to prosta relacja rodzic-dziecko, jedna Organizacja może mieć wiele Dywizji, Dywizja jest jakąś wyspecjalizowaną Organizacją. –

Odpowiedz

12

Jest to zgodne z projektem. Czytanie dokumentacji dla opcji unique_together, stwierdza, że:

It's used in the Django admin and is enforced at the database level.

Jeśli spojrzeć na stole, że podklasa tworzy, zobaczysz, że nie faktycznie mają pola, że ​​jego rodzic ma. Zamiast tego otrzymuje miękki klucz obcy do tabeli nadrzędnej z nazwą pola o nazwie [field]_ptr_id, gdzie [field] jest nazwą tabeli, którą dziedziczy się po wykluczeniu nazwy aplikacji. Tak więc twoja tabela podziału ma główny klucz obcy o nazwie organization_ptr_id.

Teraz, ponieważ unique_together jest egzekwowane na poziomie bazy danych przy użyciu ograniczenia UNIQUE, nie ma sposobu, że wiem o bazie danych, aby faktycznie zastosować to do pola, nie w tabeli.

Najlepszym rozwiązaniem jest prawdopodobnie użycie numeru Validators na poziomie logiki biznesowej lub ponowne przemyślenie schematu bazy danych w celu obsługi ograniczenia.

Edytuj: Jak zauważył Manoj, możesz także spróbować użyć opcji Model Validators, na przykład validate_unique.

+1

+1 za podanie przyczyny i powiązanie z walidatorami. Możesz również wskazać _model validations_. Na przykład 'validate_unique': http: // docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#django.db.models.Model.validate_unique –

4

[Model] Validators będzie pracować dla ciebie. Być może najprostszym, choć byłoby użyć:

class BaseOrganization(models.Model): 
    name = models.CharField(max_length="100",) 
    alias = models.SlugField() 
    class Meta: 
     abstract = True 

class Organization(BaseOrganization): 
    pass 

class Division(BaseOrganization): 
    parent_org = models.ForeignKey(Organization) 

    class Meta: 
     unique_together=['parent_org', 'alias'] 

Uwaga: zgodnie z aktualnym kodem, nie można mieć podziały podziałów.

1

Jest to rozwiązanie Niedawno używane w Django 1.6 (dzięki Manoj Govindan dla idei):

class Organization(models.Model): 
    name = models.CharField(max_length="100",) 
    alias = models.SlugField() 
    ... 

class Division(Organization): 
    parent_org = models.ForeignKey(Organization) 

    # override Model.validate_unique 
    def validate_unique(self, exclude=None):  
     # these next 5 lines are directly from the Model.validate_unique source code 
     unique_checks, date_checks = self._get_unique_checks(exclude=exclude) 
     errors = self._perform_unique_checks(unique_checks) 
     date_errors = self._perform_date_checks(date_checks) 
     for k, v in date_errors.items(): 
      errors.setdefault(k, []).extend(v) 

     # here I get a list of all pairs of parent_org, alias from the database (returned 
     # as a list of tuples) & check for a match, in which case you add a non-field 
     # error to the error list 
     pairs = Division.objects.exclude(pk=self.pk).values_list('parent_org', 'alias') 
     if (self.parent_org, self.alias) in pairs: 
       errors.setdefault(NON_FIELD_ERRORS, []).append('parent_org and alias must be unique') 

     # finally you raise the ValidationError that includes all validation errors, 
     # including your new unique constraint 
     if errors: 
      raise ValidationError(errors) 
+0

Oczywiście nie wiąże się to z żadnymi kontrolami na poziomie bazy danych, ponieważ unikalne ograniczenie w tabeli byłoby, ale pod względem sprawdzania Django to rozwiązanie sprawdziło się bezproblemowo. Jedyne, co musiałem naprawić, to upewnić się, że wykluczyłem instancję wywołującą validate_unique (stąd exclude (pk = self.pk)). –

2

nie ściśle stosują pytanie, ale jest bardzo ściśle powiązane; unique_together będzie działać, jeśli klasa podstawowa jest abstrakcyjna. Można oznaczyć klas abstrakcyjnych modeli, takich jak przy użyciu:

class Meta(): 
    abstract = True 

To zapobiegnie Django od tworzenia tabeli dla klasy, a jego pola zostaną bezpośrednio włączone w jakichkolwiek podklasy. W tej sytuacji możliwe jest unique_together, ponieważ wszystkie pola znajdują się w tej samej tabeli.

https://docs.djangoproject.com/en/1.5/topics/db/models/#abstract-base-classes

Powiązane problemy