2010-01-26 13 views
46

मेरे पास एक Django मॉडल है जो इस तरह दिखता है।Django के मॉडलफॉर्म अद्वितीय_एक साथ सत्यापन

class Solution(models.Model): 
    ''' 
    Represents a solution to a specific problem. 
    ''' 
    name = models.CharField(max_length=50) 
    problem = models.ForeignKey(Problem) 
    description = models.TextField(blank=True) 
    date = models.DateTimeField(auto_now_add=True) 

    class Meta: 
     unique_together = ("name", "problem") 

मैं मॉडल है कि इस तरह दिखता है जोड़ने के लिए एक फार्म का उपयोग करें:

class SolutionForm(forms.ModelForm): 
    class Meta: 
     model = Solution 
     exclude = ['problem'] 

मेरे समस्या यह है कि SolutionFormSolution की पुष्टि नहीं करता unique_together बाधा और है इस प्रकार, यह एक IntegrityError लौटाता है जब की कोशिश कर रहा फॉर्म को बचाओ। मुझे पता है कि मैं मैन्युअल रूप से जांचने के लिए validate_unique का उपयोग कर सकता हूं लेकिन मैं सोच रहा था कि फॉर्म सत्यापन में इसे पकड़ने का कोई तरीका है या स्वचालित रूप से एक फॉर्म त्रुटि लौटाएं।

धन्यवाद।

+2

आप यकीन है कि तुम सब कुछ सही ढंग से स्थापित कर रहे हैं क्योंकि मॉडल रूपों स्पष्ट रूप से syas के बारे में दस्तावेज़: "डिफ़ॉल्ट रूप से क्लीन() विधि मॉडल पर अनन्य, अद्वितीय_तुष्ठ या अद्वितीय_for_date | month | वर्ष के रूप में चिह्नित फ़ील्ड की विशिष्टता को मान्य करती है।" Http://docs.djangoproject.com/en/1.1/topics/forms/modelforms/# ओवरराइडिंग-क्लीन-विधि –

+2

क्या आप भाग को बाहर किए बिना इसे आजमा सकते हैं? मैन्युअल रूप से उस समस्या का चयन करें जो मुझे लगता है कि आपके विचार से निर्धारित किया गया है। –

उत्तर

12

मैं अपने फार्म के लिए एक साफ विधि जोड़कर दृश्य को संशोधित किए बिना इसे ठीक करने में कामयाब अब देखने के लिए is_valid निष्पादित करने से पहले फ़ॉर्म में एक समस्या संपत्ति जोड़ना है।


def validate_unique(self): 
    exclude = self._get_validation_exclusions() 
    exclude.remove('problem') # allow checking against the missing attribute 

    try: 
     self.instance.validate_unique(exclude=exclude) 
    except ValidationError, e: 
     self._update_errors(e.message_dict) 

अब मैं सिर्फ हमेशा यह सुनिश्चित करें कि फ़ॉर्म पर प्रदान नहीं विशेषता अभी भी उपलब्ध है, उदाहरण के लिए करते हैं:

+9

क्लॉज को छोड़कर नंगे का उपयोग न करें। यह तब भी होगा जब अपवाद डेटाबेस सर्वर को उल्का द्वारा मारा जा रहा है। इसके बजाय, "समाधान को छोड़कर" DoesNotExist: "का उपयोग करें। – GDorn

18

फ़ेलिक्स कहता है, मॉडलफॉर्म को उनके सत्यापन में unique_together बाधा की जांच करनी होगी।

हालांकि, आपके मामले में आप वास्तव में अपने रूप से उस बाधा के एक तत्व को छोड़ रहे हैं। मुझे कल्पना है कि यह आपकी समस्या है - यह कैसे बाधा की जांच करने जा रहा है, अगर इसका आधा फॉर्म पर भी नहीं है?

+2

वास्तव में यह समस्या थी। तो मुझे लगता है कि मुझे समस्या क्षेत्र सहित बिना फॉर्म में कोई त्रुटि नहीं मिल सकती है और मुझे इस मामले की मैन्युअल रूप से जांच करनी होगी। – sttwister

0

आप कुछ इस तरह करने की आवश्यकता होगी:

class SolutionForm(forms.ModelForm): 
    class Meta: 
     model = Solution 
     exclude = ['problem'] 

    def clean(self): 
     cleaned_data = self.cleaned_data 

     try: 
      Solution.objects.get(name=cleaned_data['name'], problem=self.problem) 
     except Solution.DoesNotExist: 
      pass 
     else: 
      raise ValidationError('Solution with this Name already exists for this problem') 

     # Always return cleaned_data 
     return cleaned_data 

केवल एक चीज मैं की जरूरत है:

def your_view(request): 
    if request.method == 'GET': 
     form = SolutionForm() 
    elif request.method == 'POST': 
     problem = ... # logic to find the problem instance 
     solution = Solution(problem=problem) # or solution.problem = problem 
     form = SolutionForm(request.POST, instance=solution) 
     # the form will validate because the problem has been provided on solution instance 
     if form.is_valid(): 
      solution = form.save() 
      # redirect or return other response 
    # show the form 
+0

फ़ॉर्म अभी भी 'unique_together' बाधा को मान्य नहीं करता है, संभवतः क्योंकि 'बहिष्कृत' संपत्ति में समस्या का उल्लेख किया गया है, भले ही उसके पास वैध उदाहरण – sttwister

32

मैं ModelForm की validate_unique() विधि अधिभावी द्वारा इस एक ही समस्या हल प्रारंभकर्ता पर instance=Solution(problem=some_problem)

+1

ध्यान दें कि यह केवल इस मॉडल के लिए किसी भी रूप को मान्य करता है, जबकि अंतर्निहित डेटाबेस में unique_together का उपयोग किया जाता है। इसका मतलब है कि मॉडल ऑब्जेक्ट्स का उपयोग करने वाली कोई भी चीज़ सीधे इस सत्यापन से बंधी नहीं है। – Herge

+1

संरक्षित तरीकों का उपयोग करना अच्छा है ..! – Satyajeet

1
Jarmo के जवाब की मदद से

, निम्नलिखित मेरे लिए अच्छी तरह से काम करने के लिए (Django 1.3 में) लगता है, लेकिन यह संभव मैं कुछ कोने मामले (_get_validation_exclusions आसपास के टिकट का एक बहुत देखते हैं) टूट गया है:

class SolutionForm(forms.ModelForm): 
    class Meta: 
     model = Solution 
     exclude = ['problem'] 

    def _get_validation_exclusions(self): 
     exclude = super(SolutionForm, self)._get_validation_exclusions() 
     exclude.remove('problem') 
     return exclude 

मुझे यकीन नहीं है, लेकिन यह मुझे Django बग की तरह लगता है ... लेकिन मुझे पहले से सूचित मुद्दों के आसपास देखना होगा।


संपादित करें: मैंने बहुत जल्द बात की। शायद जो मैंने ऊपर लिखा है वह कुछ परिस्थितियों में काम करेगा, लेकिन मेरे में नहीं; मैं सीधे जर्मो के जवाब का उपयोग कर समाप्त हुआ।

5

@sttwister का समाधान सही है लेकिन इसे सरल बनाया जा सकता है।

class SolutionForm(forms.ModelForm): 

    class Meta: 
     model = Solution 
     exclude = ['problem'] 

    def clean(self): 
     cleaned_data = self.cleaned_data 
     if Solution.objects.filter(name=cleaned_data['name'],   
            problem=self.problem).exists(): 
      raise ValidationError(
        'Solution with this Name already exists for this problem') 

     # Always return cleaned_data 
     return cleaned_data 

एक बोनस के रूप आप डुप्लिकेट के मामले में वस्तु प्राप्त नहीं है, लेकिन केवल जाँच अगर यह डेटाबेस प्रदर्शन का एक छोटा सा बचत में मौजूद है।

0

आपको त्रुटि संदेश एक name क्षेत्र के साथ जुड़े होने के लिए चाहते हैं (और उसके आगे दिखाई दे) हैं:

def clean(self): 
    cleaned_data = super().clean() 
    name_field = 'name' 
    name = cleaned_data.get(name_field) 

    if name: 
     if Solution.objects.filter(name=name, problem=self.problem).exists(): 
      cleaned_data.pop(name_field) # is also done by add_error 
      self.add_error(name_field, _('There is already a solution with this name.')) 

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