2010-10-05 30 views
7

Sử dụng đoạn mã sau:Lỗi sử dụng một lĩnh vực lớp cơ sở trong lớp con unique_together tùy chọn 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'] 
     ... 

Cố gắng syncdb cho tôi lỗi này:

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. 

Any help is appreciated,

Cảm ơn,

Eric

+0

Bạn có thể giải thích yêu cầu nhiều hơn, không thể hiểu nhu cầu kế thừa tổ chức và có ngoại khóa cho cùng một mô hình cơ sở. –

+0

Đó là một mối quan hệ cha-con đơn giản mà một tổ chức có thể có nhiều bộ phận, một bộ phận là một loại tổ chức chuyên môn. –

Trả lời

12

Đây là theo thiết kế. Đọc tài liệu hướng dẫn cho các tùy chọn unique_together, nó khẳng định rằng:

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

Nếu bạn nhìn vào bảng mà một lớp con tạo ra, bạn sẽ thấy rằng nó không thực sự có các lĩnh vực mà mẹ có. Thay vào đó, nó sẽ nhận được Khóa ngoại mềm mềm cho bảng cha với tên trường được gọi là [field]_ptr_id, trong đó [field] là tên của bảng mà bạn đang kế thừa từ loại trừ tên ứng dụng. Vì vậy, bảng phân chia của bạn có khóa chính chính được gọi là organization_ptr_id.

Bây giờ vì unique_together được thực thi ở cấp cơ sở dữ liệu sử dụng ràng buộc UNIQUE, không có cách nào tôi biết để cơ sở dữ liệu thực sự áp dụng cho trường không có trong bảng.

Đặt cược tốt nhất của bạn có thể thông qua việc sử dụng Validators ở cấp logic nghiệp vụ của bạn hoặc suy nghĩ lại lược đồ cơ sở dữ liệu của bạn để hỗ trợ ràng buộc.

Chỉnh sửa: Như Manoj đã chỉ ra, bạn cũng có thể thử sử dụng Model Validators chẳng hạn như validate_unique.

+1

+1 để đề cập đến lý do và liên kết với người xác thực. Bạn cũng có thể muốn chỉ ra _model validations_. Ví dụ 'validate_unique': http: // docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#django.db.models.Model.validate_unique –

4

[Mẫu] Trình xác thực sẽ phù hợp với bạn. Tuy nhiên, có lẽ đơn giản nhất là sử dụng:

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'] 

Lưu ý: giống như mã hiện tại của bạn, bạn không thể có phân mục của các bộ phận.

1

Đây là một giải pháp Gần đây tôi đã được sử dụng trong Django 1,6 (nhờ Manoj Govindan cho ý tưởng):

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

Rõ ràng điều này không liên quan đến bất kỳ kiểm tra mức cơ sở dữ liệu nào, như một ràng buộc duy nhất trong một bảng, nhưng về xác nhận Django, giải pháp này làm việc liên tục cho tôi. Một trong những gotcha tôi đã phải sửa chữa là để đảm bảo loại trừ dụ dụ gọi validate_unique (do đó loại trừ (pk = self.pk)). –

2

này không áp dụng đúng các câu hỏi nhưng có liên quan rất chặt chẽ; unique_together sẽ hoạt động nếu lớp cơ sở là trừu tượng. Bạn có thể đánh dấu các lớp mô hình trừu tượng như vậy bằng cách sử dụng:

class Meta(): 
    abstract = True 

Điều này sẽ ngăn django tạo bảng cho lớp và các trường của nó sẽ được bao gồm trực tiếp trong bất kỳ lớp con nào. Trong tình huống này, unique_together là có thể vì tất cả các trường đều nằm trong cùng một bảng.

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

Các vấn đề liên quan