models.py đang trở nên khổng lồ, cách tốt nhất để chia nhỏ nó là gì?


91

Chỉ dẫn từ người giám sát của tôi: "Tôi muốn tránh đặt bất kỳ logic nào vào trong models.py. Từ đây trở đi, hãy sử dụng nó như chỉ các lớp để truy cập cơ sở dữ liệu và giữ tất cả logic trong các lớp bên ngoài sử dụng các lớp mô hình hoặc bọc chúng."

Tôi cảm thấy như đây là một con đường sai lầm để đi. Tôi cảm thấy rằng việc giữ logic ra khỏi các mô hình chỉ để giữ cho tệp nhỏ là một ý tưởng tồi. Nếu logic là tốt nhất trong mô hình, đó là nơi nó thực sự nên đi bất kể kích thước tệp.

Vì vậy, có một cách đơn giản để chỉ cần sử dụng bao gồm? Trong PHP-speak, tôi muốn đề xuất với người giám sát rằng chúng tôi vừa models.pyđưa vào () các lớp mô hình từ những nơi khác. Về mặt khái niệm, điều này sẽ cho phép các mô hình có tất cả logic mà chúng ta muốn, nhưng vẫn giữ kích thước tệp giảm xuống thông qua việc tăng số lượng tệp (dẫn đến ít vấn đề kiểm soát sửa đổi hơn như xung đột, v.v.).

Vì vậy, có cách nào đơn giản để loại bỏ các lớp mô hình khỏi tệp models.py, nhưng các mô hình vẫn hoạt động với tất cả các công cụ Django không? Hoặc, có một giải pháp hoàn toàn khác nhưng thanh lịch cho vấn đề chung của tệp models.py "lớn" không? Mội thông tin đầu vào đều sẽ được xem xét kĩ.


7
Bạn biết câu lệnh nhập khẩu, phải không?
balpha

7
Tái bút. Ý tôi không phải là xúc phạm, tôi chỉ muốn biết bạn đang ở đâu.
balpha

1
Có, nhưng tôi không biết liệu các công cụ quản trị của django có hoạt động hay không nếu chỉ sử dụng câu lệnh nhập để kéo Mô hình vào. Tôi muốn hỏi ở đây hơn là dành nhiều thời gian để thử sử dụng nhập khẩu ole đơn giản chỉ để tìm ra các công cụ của django không hoạt động tốt với chúng. Tôi thừa nhận tôi mới đến python và django, vì vậy tôi có lẽ chỉ tại một sự hiểu biết đơn giản của câu lệnh import ...
Eddified

Câu trả lời:


64

Django được thiết kế để cho phép bạn xây dựng nhiều ứng dụng nhỏ thay vì một ứng dụng lớn.

Bên trong mỗi ứng dụng lớn là rất nhiều ứng dụng nhỏ đang đấu tranh để được miễn phí.

Nếu bạn models.pycảm thấy lớn, bạn đang làm quá nhiều. Dừng lại. Thư giãn. Phân hủy.

Tìm các thành phần hoặc phần ứng dụng nhỏ nhỏ hơn, có khả năng tái sử dụng. Bạn không cần phải thực sự sử dụng lại chúng. Chỉ cần nghĩ về chúng có khả năng tái sử dụng.

Xem xét các đường dẫn nâng cấp của bạn và phân rã các ứng dụng mà bạn có thể muốn thay thế vào một ngày nào đó. Bạn không thực sự phải thay thế chúng, nhưng bạn có thể coi chúng như một "mô-đun" lập trình độc lập có thể được thay thế bằng thứ gì đó mát mẻ hơn trong tương lai.

Chúng tôi có khoảng một chục ứng dụng, mỗi ứng dụng model.pykhông quá 400 dòng mã. Tất cả chúng đều khá tập trung vào ít hơn khoảng nửa tá định nghĩa lớp rời rạc. (Đây không phải là những giới hạn cứng, chúng là những quan sát về mã của chúng tôi.)

Chúng tôi phân hủy sớm và thường xuyên.


1
đúng vào điểm. bất kỳ ứng dụng web không tầm thường nào sẽ là một số 'ứng dụng' nhỏ. mất một gợi ý của contrib và các ứng dụng phổ biến khác, xác thực người dùng là một trong những ứng dụng, gắn thẻ là một khác, hồ sơ người dùng một hơn, vv
Javier

4
Mặc dù đây là cách "đúng" và hữu ích khi biết, nhưng nó không hoàn toàn là những gì tôi đang tìm kiếm. Tôi xin lỗi nếu không có cách nào để biết loại câu trả lời mà tôi đang tìm kiếm. :)
Chỉnh sửa vào

@Eddified: nếu bạn không làm điều này, nó sẽ chỉ trở nên tồi tệ hơn. Bắt đầu tách ngay bây giờ.
S.Lott

Thật buồn cười, ngay lúc này tôi đang nghe Jacob Kaplan Moss (tại OSCON) giải thích chính xác điều này một cách chi tiết tuyệt vời và hợp lý ;-).
Alex Martelli,

13
Câu trả lời của Glenn Maynard tốt hơn nhiều về câu trả lời này. Chia một ứng dụng web phức tạp thành nhiều ứng dụng chắc chắn là một phương pháp hay, nhưng việc cấu trúc lại tệp model.py trong VÒNG một ứng dụng cũng vậy. Hai hành động có thể trực giao.
Erik

108

Việc các lớp mô hình chứa các phương thức hoạt động trên mô hình là điều tự nhiên. Nếu tôi có mô hình Sách, với một phương thức book.get_noun_count(), thì đó là nơi nó thuộc về - tôi không muốn phải viết " get_noun_count(book)", trừ khi về bản chất phương thức này thuộc về một số gói khác. (Nó có thể - ví dụ: nếu tôi có một gói để truy cập API của Amazon với " get_amazon_product_id(book)".)

Tôi rưng rưng khi tài liệu của Django đề xuất đưa các mô hình vào một tệp duy nhất và tôi đã mất vài phút ngay từ đầu để tìm ra cách tách nó thành một gói con thích hợp.

site/models/__init__.py
site/models/book.py

__init__.py giống như:

from .book import Book

vì vậy tôi vẫn có thể viết "from site.models import Sách".


Phần sau chỉ bắt buộc đối với các phiên bản trước Django 1.7, xem https://code.djangoproject.com/ticket/3591

Mẹo duy nhất là bạn cần đặt ứng dụng của từng mô hình một cách rõ ràng, do một lỗi trong Django: nó giả định rằng tên ứng dụng là mục nhập từ thứ ba đến cuối cùng trong đường dẫn mô hình. "site.models.Book" cho kết quả là "site", chính xác; "site.models.book.Book" làm cho nó nghĩ rằng tên ứng dụng là "mô hình". Đây là một vụ hack khá khó chịu về phần của Django; nó có thể sẽ tìm kiếm trong danh sách các ứng dụng đã cài đặt để tìm kiếm tiền tố khớp.

class Book(models.Model):
    class Meta: app_label = "site"

Bạn có thể sử dụng một lớp cơ sở hoặc siêu cát để tổng quát hóa điều này, nhưng tôi chưa bận tâm đến điều đó.


2
+1 Tôi đã sử dụng nó thành công. Mặc dù S. Lott phù hợp với nhiều ứng dụng là một ý tưởng hay, nhưng đây là giải pháp ở đây và bây giờ.
Alexander Ljungberg

35
Tôi không thấy nhiều lợi ích của việc chia nhỏ mọi thứ thành nhiều ứng dụng, khi các mô hình của bạn có liên quan chặt chẽ và thực chất.
Glenn Maynard

2
Điều này làm tôi thích thú. Tôi đọc liên kết django wiki được đăng và thấy điều này: "Điều này đã được xác minh là hoạt động mà không có app_labels lớp Meta, trong nhánh chính hiện tại." Vì vậy, điều đó có nghĩa là nếu bạn đang làm việc với nhánh chính, chúng tôi có thể loại bỏ nội dung Meta: app_label? Thật khó hiểu vì nó là sau khi bình luận về vé để giải quyết vấn đề này.
Dan.StackOverflow

2
Tôi vừa thử nghiệm với thân cây (tính đến đầu ngày hôm nay, r11286); nếu app_name không được đặt, thì mô hình chỉ đơn giản là không hiển thị trong "sqlall appname" và có thể sẽ không được tạo bởi syncdb (nhưng tôi không sử dụng nên không thể kiểm tra nó). Đó là một trường hợp lỗi khá khó hiểu, vì nó không gây ra bất kỳ lỗi nào; nó chỉ âm thầm không hiện ra.
Glenn Maynard

2
Wow, gần 10 năm sau và tôi vẫn thích giải pháp này. Đồng ý rằng đó là một cách tiếp cận tốt hơn nhiều so với việc chia nhỏ mã của bạn thành các ứng dụng nhỏ hơn, theo ý kiến ​​của tôi, điều này có thể dẫn đến một cơ sở mã khó lý giải.
Michael Hays

5

Tôi không thể hiểu được bạn có thể gặp phải vấn đề nào trong số nhiều vấn đề có thể xảy ra. Dưới đây là một số khả năng có câu trả lời:

  • nhiều mô hình trong cùng một tệp

    Đặt chúng thành các tệp riêng biệt. Nếu có phụ thuộc, hãy sử dụng nhập để lấy các mô hình bổ sung.

  • các hàm logic / tiện ích không liên quan trong models.py

    Đặt logic bổ sung vào các tệp riêng biệt.

  • phương pháp tĩnh để chọn một số trường hợp mô hình từ cơ sở dữ liệu

    Tạo một Trình quản lý mới trong một tệp riêng biệt.

  • các phương pháp rõ ràng liên quan đến mô hình

    save, __unicode__ và get_absolute_url là những ví dụ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.