2013-03-05 9 views
6

Mam użytkownikom dzielić modelu coś jak poniżej:Django zwyczaj unikalny razem ograniczenie

class Share(models.Model): 
    sharer = models.ForeignKey(User, verbose_name=_("Sharer"), related_name='sharer') 
    receiver = models.ForeignKey(User, verbose_name=_("Receiver"), related_name='receiver') 

    class Meta: 
     unique_together = (("sharer", "receiver"), ("receiver", "sharer")) 

chcę zapisać pojedynczy obiekt do współdzielenia (S) i odbiornika (R) (kolejność nie matters lub RS SR). ale powyżej unique_together nie spełni tego; Załóżmy, że R-S znajduje się w bazie danych, a następnie, jeśli zapiszę S-R, nie otrzymam walidacji. W tym celu napisałem niestandardową, unikatową walidację modelu Share.

def validate_unique(
     self, *args, **kwargs): 
      super(Share, self).validate_unique(*args, **kwargs) 
      if self.__class__.objects.filter(Q(sharer=self.receiver, receiver=self.sharer)).exists(): 
       raise ValidationError(
        { 
         NON_FIELD_ERRORS: 
         ('Share with same sharer and receiver already exists.',) 
        } 
       ) 

    def save(self, *args, **kwargs): 
     # custom unique validate 
     self.validate_unique() 
     super(Share, self).save(*args, **kwargs) 

Ta metoda działa prawidłowo podczas normalnego użytkowania.

Problem: mam algorytm dopasowywania który dostaje akcji i żądań odbiornika oraz zapisanie obiekt Poleć (albo S-R lub R-S), a następnie wysłać do nich odpowiedzi (obiekt zakładowego) niemal w tym samym czasie. Podczas sprawdzania duplikacji z zapytaniem (brak poziomu bazy danych) zajmuje to trochę czasu, więc na koniec mam 2 obiekty S-R i R-S.

Potrzebuję rozwiązania tego problemu, że dla sharer S i odbiornika R I można zapisać tylko obiekt pojedynczego udziału, albo S-R lub R-S jeszcze uzyskać błąd sprawdzania poprawności (jak IntegrityError z databse).

Django = 1,4, Database = Postgresql

Odpowiedz

4

Prawdopodobnie może rozwiązać ten z PostgreSQL indexes on expressions ale tu jest inny sposób:

class Share(models.Model): 
    sharer = models.ForeignKey(User) 
    receiver = models.ForeignKey(User), related_name='receiver') 
    key = models.CharField(max_length=64, unique=True) 

    def save(self, *args, **kwargs): 
     self.key = "{}.{}".format(*sorted([self.sharer_id, self.receiver_id])) 
     super(Share, self).save(*args, **kwargs) 

Ale to oczywiście nie będzie działać po zmianie wartości z QuerySet.update metody . Możesz również spojrzeć na django-denorm, rozwiązuje to za pomocą wyzwalaczy.

+0

Dziękuję za odpowiedź. Miałem 2 rozwiązania. Jeden do obsłużenia go przez unikalny numer żądania (podczas dopasowywania w inkrementowanym identyfikatorze Redis) i zapisania pierwszego udziału obj z niższym żądaniem #, a następnie oczekiwania i uzyskania share_obj dla wyższego żądania #. ale rozwiązałem go za pomocą drugiego rozwiązania (opisanego przez ciebie), aby posortować listę nazw użytkowników zarówno sharer, jak i receive, w ten sposób otrzymam zawsze ten sam wzorzec sharer i receiver. Zapiszę żądanie i jeśli otrzymam IntegrityError przez postgresql, wycofam transakcję i zabezpieczyłem już zapisany obiekt S-R. :) –

Powiązane problemy