2013-03-05 11 views
6

मैं एक उन है का हिस्सा नीचे की तरह मॉडल कुछ:Django कस्टम अद्वितीय एक साथ बाधा

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")) 

मैं हिस्सेदार (एस) और रिसीवर (आर) के लिए एक वस्तु (सहेजना चाहते आदेश नहीं मामलों रुपये या एसआर)। लेकिन अद्वितीय से ऊपर यह पूरा नहीं करेगा; मान लीजिए आर-एस डेटाबेस में है और फिर यदि मैं एस-आर बचाता हूं तो मुझे इसके लिए सत्यापन नहीं मिलेगा। इसके लिए मैंने शेयर मॉडल के लिए कस्टम अद्वितीय सत्यापन लिखा है।

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) 

यह विधि सामान्य उपयोग में ठीक काम करती है।

समस्या: मैं एक मिलान एल्गोरिथ्म जो एक हिस्से का और एक रिसीवर के अनुरोध हो जाता है और शेयर वस्तु (या तो एस आर या आर एस) की बचत होती है तो उन्हें प्रतिक्रिया (शेयर वस्तु) भेजने पर लगभग एक ही समय है। चूंकि मैं क्वेरी के साथ डुप्लिकेशन जांच रहा हूं (डेटाबेस स्तर नहीं) इसमें समय लगता है, इसलिए अंत में मेरे पास 2 ऑब्जेक्ट्स एस-आर और आर-एस हैं।

मुझे इसके लिए कुछ समाधान चाहिए कि एक शेयरर एस और रिसीवर आर के लिए मैं केवल एक शेयर ऑब्जेक्ट को सहेज सकता हूं, या तो एस-आर या आर-एस को कुछ सत्यापन त्रुटि मिलती है (जैसे डाटाबेस की इंटीग्रिटी एरर)।

Django = 1.4, डाटाबेस = Postgresql

उत्तर

4

आप शायद इस PostgreSQL के indexes on expressions साथ हल कर सकते थे, लेकिन यहाँ एक और तरीका है:

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) 

लेकिन अगर आप QuerySet.update विधि के साथ मूल्यों को बदल यह स्पष्ट रूप से कार्य नहीं करेगा । आप django-denorm पर भी देख सकते हैं, यह ट्रिगर्स के साथ हल करता है।

+0

आपके उत्तर का धन्यवाद। मेरे पास 2 समाधान थे। इसे अनन्य अनुरोध संख्या से संभालने के लिए (रेडिस कैश में वृद्धि हुई आईडी में मिलान करते समय) और निचले अनुरोध # के पहले शेयर obj को सहेजें, फिर प्रतीक्षा करें और उच्च अनुरोध के लिए share_obj प्राप्त करें #। लेकिन मैंने इसे दूसरे समाधान (आपके द्वारा वर्णित) द्वारा हल किया है ताकि दोनों शेयरर के उपयोगकर्ता नामों की सूची को क्रमबद्ध किया जा सके और इस तरह से मैं हमेशा शेयरर और रिसीवर के समान पटर प्राप्त करूंगा। मैं अनुरोध को सहेज लेगा और अगर postgresql द्वारा IntegrityError प्राप्त करता हूं तो मैं लेन-देन रोलबैक करता हूं और safley पहले से ही एस-आर ऑब्जेक्ट सहेजा जाता है। :) –

संबंधित मुद्दे