2010-08-15 27 views
7

Tôi thấy một số ppl gặp vấn đề này trước tôi, nhưng trên các phiên bản cũ của Django, và tôi đang chạy trên 1.2.1.Django unique_together không hoạt động với ForeignKey = None

Tôi có một mô hình trông giống như:

class Category(models.Model): 
objects = CategoryManager() 

name = models.CharField(max_length=30, blank=False, null=False) 
parent = models.ForeignKey('self', null=True, blank=True, help_text=_('The direct parent category.')) 

class Meta: 
    unique_together = ('name', 'parent') 

Bất cứ khi nào tôi cố gắng để tiết kiệm trong quản trị một loại với cha mẹ thiết lập để Không, nó vẫn hoạt động khi có một loại với cùng tên và bộ cha mẹ thành Không.

Ý tưởng về cách giải quyết điều này một cách duyên dáng?

Trả lời

9

Ràng buộc cùng nhau duy nhất được thực thi ở cấp cơ sở dữ liệu và có vẻ như công cụ cơ sở dữ liệu của bạn không áp dụng ràng buộc cho giá trị null.

Trong Django 1.2, bạn có thể xác định clean method để mô hình của bạn cung cấp xác thực tùy chỉnh. Trong trường hợp của bạn, bạn cần một cái gì đó mà kiểm tra cho các loại khác có cùng tên bất cứ khi nào cha mẹ là Không có.

class Category(models.Model): 
    ... 
    def clean(self): 
     """ 
     Checks that we do not create multiple categories with 
     no parent and the same name. 
     """ 
     from django.core.exceptions import ValidationError 
     if self.parent and Category.objects.filter(name=self.name).exists(): 
      raise ValidationError("Another Category with name=%s and no parent already exists % self.name) 

Nếu bạn đang chỉnh sửa danh mục thông qua quản trị viên Django, phương pháp sạch sẽ được gọi tự động. Theo quan điểm của riêng bạn, bạn phải gọi category.fullclean().

+0

Cách tiếp cận chung có vẻ tốt ở đây, nhưng tôi không theo logic của 'if self.parent và Category.objects.filter (name = self.name) .exists():' Điều đó trông giống như tôi đang kiểm tra xem cha mẹ có tồn tại hay không và một danh mục khác có cùng tên tồn tại. Làm thế nào là những gì chúng tôi muốn? Không nên điều này thay vì là một cái gì đó như (chưa được kiểm tra) 'nếu self.parent == Không có và FolderUpload.objects.filter (tên = self.name, parent = None) .exists():'? –

+0

Tôi nghĩ bạn nói đúng. Tôi sẽ sử dụng parent_id__is null = True thay vì parent = None. Nó có thể cần một loại trừ() để bỏ qua đối tượng hiện tại là tốt. – Alasdair

+0

Tôi sẽ vắng mặt trong một tuần, vì vậy sẽ không thể sửa câu trả lời. Vui lòng chỉnh sửa nếu bạn muốn/có thể. – Alasdair

5

Tôi có vấn đề mà quá và giải quyết nó bằng cách tạo ra một siêu mẫu với clean phương pháp (như Alasdair gợi ý) và sử dụng nó như là lớp cơ sở cho tất cả các mô hình của tôi:

class Base_model(models.Model): 
    class Meta: 
    abstract=True 

    def clean(self): 
    """ 
    Check for instances with null values in unique_together fields. 
    """ 
    from django.core.exceptions import ValidationError 

    super(Base_model, self).clean() 

    for field_tuple in self._meta.unique_together[:]: 
     unique_filter = {} 
     unique_fields = [] 
     null_found = False 
     for field_name in field_tuple: 
      field_value = getattr(self, field_name) 
      if getattr(self, field_name) is None: 
       unique_filter['%s__isnull'%field_name] = True 
       null_found = True 
      else: 
       unique_filter['%s'%field_name] = field_value 
       unique_fields.append(field_name) 
     if null_found: 
      unique_queryset = self.__class__.objects.filter(**unique_filter) 
      if self.pk: 
       unique_queryset = unique_queryset.exclude(pk=self.pk) 
      if unique_queryset.exists(): 
       msg = self.unique_error_message(self.__class__, tuple(unique_fields)) 
       raise ValidationError(msg) 
Các vấn đề liên quan