2009-09-07 25 views
5

Tôi muốn đảm bảo một đối tượng là duy nhất và để ném lỗi khi người dùng cố gắng lưu nó (ví dụ: thông qua quản trị viên) nếu không? Theo duy nhất, tôi có nghĩa là một số thuộc tính của đối tượng có thể giữ các giá trị giống như các đối tượng khác, nhưng chúng không thể TẤT CẢ giống hệt với các giá trị của đối tượng khác.DRY đối tượng duy nhất trong Django

Nếu tôi không nhầm, tôi có thể làm điều này như sau:

class Animal(models.Model): 
    common_name = models.CharField(max_length=150) 
    latin_name = models.CharField(max_length=150) 
    class Meta: 
     unique_together = ("common_name", "latin_name") 

Nhưng sau đó mỗi khi tôi cấu trúc lại mô hình (ví dụ như để thêm một lĩnh vực mới, hoặc để thay đổi tên của một lĩnh vực đang tồn tại), Tôi cũng phải chỉnh sửa danh sách các trường trong dấu ngoặc đơn được gán cho unique_together. Với một mô hình đơn giản, đó là OK, nhưng với một mô hình đáng kể, nó trở thành một rắc rối thực sự trong quá trình tái cấu trúc.

Làm cách nào để tránh phải lặp lại việc nhập danh sách tên trường trong dấu ngoặc đơn unique_together? Có cách nào để chuyển danh sách các trường của mô hình đến một biến và gán biến đó cho unique_together thay thế không?

+1

+1 - tuyệt vời câu hỏi. Tôi không nghĩ rằng bạn có thể, nhưng tôi quan tâm để nghe ý kiến ​​của người khác. –

+0

+1 - Nó thực sự là thú vị nếu ai đó có thể tìm thấy một giải pháp tốt đẹp. Tôi đã thử nhưng không thể làm cho nó hoạt động thông qua sự phản chiếu, bởi vì bạn không thể đọc các thuộc tính từ lớp Animal (điều này là hiển nhiên bởi vì Animal không được định nghĩa hoàn toàn tại thời điểm đó). – FlorianH

+0

jtiai trên irc: //irc.freenode.net/django vui lòng dành thời gian để thảo luận câu hỏi và đề nghị tôi có thể thêm lớp "AllUniqueModel" của riêng mình, kế thừa tiêu chuẩn "Mô hình" và tạo một số phép thuật metaclass để tiêm tất cả các trường trong unique_togerther sau khi chúng được xử lý theo quy trình tạo tiêu chuẩn. ' Tôi không hoàn toàn chắc chắn những gì jtiai có nghĩa là do đó, nhưng nó có vẻ giống như một giải pháp phức tạp hơn tôi đã hy vọng. – sampablokuper

Trả lời

4

mô hình Refactoring là một điều khá tốn kém để làm:

  • Bạn sẽ cần phải thay đổi tất cả các mã sử dụng mô hình của bạn từ tên trường tương ứng với đối tượng thuộc tính
  • Bạn sẽ phải thay đổi cơ sở dữ liệu của bạn bằng tay từ Django không thể làm điều này cho bạn (ít nhất là phiên bản tôi đã sử dụng lần cuối cùng khi tôi làm việc với Django không thể)

Do đó tôi nghĩ việc cập nhật danh sách các tên trường duy nhất trong lớp meta mô hình là vấn đề ít nhất bạn nên lo lắng bout.

EDIT: Nếu bạn thực sự muốn làm điều này và tất cả lĩnh vực của bạn phải là "độc đáo với nhau", sau đó anh chàng tại freenode là đúng và bạn sẽ phải viết một metaclass tùy chỉnh. Điều này là khá phức tạp và errorprone, cộng với nó có thể làm cho mã của bạn không tương thích với các phiên bản tương lai của Django.

"ORM" của Django được điều khiển bởi metaclass ModelBase (django.db.models.base.ModelBase) của lớp cơ sở chung Model. Lớp này chịu trách nhiệm đưa định nghĩa lớp của bạn với tất cả các trường và thông tin Meta và tạo lớp bạn sẽ sử dụng trong mã của bạn sau này.

Đây là một công thức về cách bạn có thể đạt được mục tiêu của bạn:

  1. Subclass ModelBase sử dụng metaclass của riêng bạn.
  2. Override phương pháp __new__(cls, name, bases, dict)
  3. Inspect dict để thu thập các Meta thành viên (dict["Meta"]) cũng như tất cả các thành viên lĩnh vực
  4. Đặt meta.unique_together dựa trên tên của các trường bạn thu thập được.
  5. Gọi thực hiện siêu (ModelBase.__new__)
  6. Sử dụng metaclass tùy chỉnh cho tất cả các mô hình duy nhất của bạn bằng cách sử dụng thành viên kỳ diệu __metaclass__ = MyMetaclass (hoặc lấy được một lớp cơ sở trừu tượng mở rộng Model và trọng metaclass)
+1

Ở giai đoạn tạo mẫu, các mô hình tái cấu trúc có giá rẻ nhưng mã nhân đôi thì đắt tiền, do đó câu hỏi của tôi. Rõ ràng, trong sản xuất, đó là một vấn đề khác, nhưng nếu một câu trả lời tốt cho câu hỏi của tôi có thể được tìm thấy, thì điều này sẽ ít nhất giảm * một * các bước tôi phải thực hiện khi tái cấu trúc trong sản xuất. – sampablokuper

+1

Xem câu trả lời cập nhật của tôi cho câu trả lời dài, có thể bạn sẽ hiểu rằng nó có thể quá phức tạp để làm. –

+2

Cảm ơn bạn đã cập nhật câu trả lời của mình. Vâng, tôi thấy khá phức tạp để đạt được điều này. Hmm. Nó sẽ rất tuyệt nếu Django đơn giản có thể cung cấp tùy chọn để chỉ định ** unique \ _together = (all) ** hoặc somesuch, hoặc nếu nó có thể cho phép các mô hình thực hiện nội tâm trên bản thân để tạo danh sách trường để chuyển tới các tùy chọn Meta, v.v. . Hoặc cả hai :) – sampablokuper

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