models.py menjadi besar, apa cara terbaik untuk memecahnya?

91

Petunjuk dari supervisor saya: "Saya ingin menghindari menempatkan logika apa pun di models.py. Mulai saat ini, mari kita gunakan itu hanya sebagai kelas untuk mengakses database, dan menyimpan semua logika di kelas eksternal yang menggunakan kelas model, atau membungkusnya."

Saya merasa ini adalah cara yang salah untuk pergi. Saya merasa bahwa menjaga logika dari model hanya untuk menjaga file tetap kecil adalah ide yang buruk. Jika logikanya paling baik dalam modelnya, di situlah logika harus digunakan terlepas dari ukuran file.

Jadi apakah ada cara sederhana untuk hanya menggunakan include? Dalam bahasa PHP, saya ingin mengusulkan kepada supervisor bahwa kita baru saja models.pymenyertakan () kelas model dari tempat lain. Secara konseptual, ini akan memungkinkan model untuk memiliki semua logika yang kita inginkan, namun tetap memperkecil ukuran file melalui peningkatan jumlah file (yang menyebabkan lebih sedikit masalah kontrol revisi seperti konflik, dll.).

Jadi, apakah ada cara sederhana untuk menghapus kelas model dari berkas models.py, tapi masih mempunyai model bekerja dengan semua perkakas Django? Atau, apakah ada solusi yang benar-benar berbeda namun elegan untuk masalah umum file "large" models.py? Setiap masukan akan kami hargai.

Eddified
sumber
7
Anda tahu pernyataan impor, bukan?
balpha
7
PS. Saya tidak bermaksud menyinggung itu, saya hanya ingin tahu di mana Anda berada.
balpha
1
Ya, tapi saya tidak tahu apakah perkakas admin django akan bekerja hanya dengan menggunakan pernyataan import untuk menarik Model. Saya lebih suka bertanya di sini daripada menghabiskan banyak waktu mencoba menggunakan impor ole biasa hanya untuk mengetahui alat django tidak bekerja dengan baik dengannya. Saya akui saya lebih baru mengenal python dan django, jadi saya mungkin hanya memiliki pemahaman sederhana tentang pernyataan impor ...
Diedit

Jawaban:

64

Django dirancang untuk membiarkan Anda membangun banyak aplikasi kecil daripada satu aplikasi besar.

Di dalam setiap aplikasi besar ada banyak aplikasi kecil yang berjuang untuk menjadi gratis.

Jika Anda models.pymerasa besar, Anda melakukan terlalu banyak. Berhenti. Bersantai. Membusuk.

Temukan komponen atau bagian aplikasi kecil yang lebih kecil dan berpotensi dapat digunakan kembali. Anda tidak harus benar - benar menggunakannya kembali. Anggap saja mereka berpotensi dapat digunakan kembali.

Pertimbangkan jalur peningkatan Anda dan dekomposisi aplikasi yang mungkin ingin Anda ganti suatu hari nanti. Anda tidak harus benar - benar menggantinya, tetapi Anda dapat menganggapnya sebagai "modul" pemrograman yang berdiri sendiri yang mungkin akan diganti dengan sesuatu yang lebih keren di masa mendatang.

Kami memiliki sekitar selusin aplikasi, masing model.py- masing tidak lebih dari 400 baris kode. Mereka semua cukup fokus pada kurang dari setengah lusin definisi kelas yang berbeda. (Ini bukan batasan yang sulit, ini adalah pengamatan tentang kode kita.)

Kami membusuk lebih awal dan sering.

S. Lott
sumber
1
tepat sasaran. aplikasi web non-sepele apa pun akan menjadi beberapa 'aplikasi' kecil. ambil petunjuk tentang kontrib dan aplikasi populer lainnya, otentikasi pengguna adalah satu aplikasi, penandaan adalah yang lain, profil pengguna satu lagi, dll.
Javier
4
Meskipun ini adalah cara yang "benar", dan sangat membantu untuk diketahui, ini bukanlah yang saya cari. Saya minta maaf jika tidak ada cara untuk mengetahui jawaban seperti apa yang saya cari. :)
Eddified
@Edified: jika Anda tidak melakukan ini, itu hanya akan menjadi lebih buruk. Mulailah membelah sekarang.
S. Lotot
Cukup lucu, saat ini saya sedang mendengarkan Jacob Kaplan Moss (di OSCON) menjelaskan hal ini dengan sangat rinci dan sangat tepat ;-).
Alex Martelli
13
Jawaban Glenn Maynard jauh lebih baik untuk yang satu ini. Membagi aplikasi web yang kompleks menjadi banyak aplikasi tentu saja merupakan praktik yang baik, tetapi begitu juga dengan memfaktorkan ulang file model.py DI DALAM aplikasi. Kedua tindakan tersebut bisa ortogonal.
Erik
108

Wajar jika kelas model berisi metode untuk beroperasi pada model. Jika saya memiliki model Buku, dengan metode book.get_noun_count(), di situlah tempatnya - saya tidak ingin menulis " get_noun_count(book)", kecuali metode tersebut secara intrinsik dimiliki oleh beberapa paket lain. (Mungkin - misalnya, jika saya memiliki paket untuk mengakses API Amazon dengan " get_amazon_product_id(book)".)

Saya merasa ngeri ketika dokumentasi Django menyarankan untuk meletakkan model dalam satu berkas, dan saya mengambil beberapa menit dari awal untuk mencari tahu bagaimana membaginya menjadi sub-paket yang tepat.

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

__init__.py seperti:

from .book import Book

jadi saya masih bisa menulis "dari site.models import Book".


Berikut ini hanya diperlukan untuk versi sebelum Django 1.7, lihat https://code.djangoproject.com/ticket/3591

Trik satu-satunya adalah Anda perlu secara eksplisit menyetel aplikasi setiap model, karena adanya bug di Django: ini mengasumsikan bahwa nama aplikasi adalah entri ketiga hingga terakhir di jalur model. "site.models.Book" menghasilkan "situs", yang benar; "site.models.book.Book" membuatnya mengira nama aplikasi adalah "model". Ini adalah retasan yang cukup buruk di pihak Django; itu mungkin harus mencari daftar aplikasi yang diinstal untuk pencocokan awalan.

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

Anda mungkin bisa menggunakan kelas dasar atau metaclass untuk menggeneralisasi ini, tapi saya belum mempedulikannya.

Glenn Maynard
sumber
2
+1 Saya telah menggunakan ini dengan sukses. Meskipun S. Lott benar di beberapa aplikasi sebagai ide yang bagus, ini adalah solusi di sini dan sekarang.
Alexander Ljungberg
35
Saya tidak melihat banyak manfaat dari membagi berbagai hal menjadi beberapa aplikasi, jika model Anda terkait erat dan secara intrinsik.
Glenn Maynard
2
Ini menarik minat saya. Saya membaca link wiki django scompt yang diposting dan menemukan ini: "Ini telah diverifikasi untuk bekerja tanpa label_aplikasi kelas Meta, di cabang utama saat ini." Jadi apakah itu berarti jika Anda bekerja dengan cabang utama kita dapat membuang item Meta: app_label? Ini membingungkan karena setelah komentar tentang tiket untuk menyelesaikan masalah ini.
Dan.StackOverflow
2
Saya baru saja menguji dengan trunk (seperti sebelumnya hari ini, r11286); jika app_name tidak disetel, modelnya tidak muncul di "sqlall appname" dan mungkin tidak akan dibuat oleh syncdb (tapi saya tidak menggunakannya jadi saya tidak bisa mengujinya). Ini kasus kesalahan yang cukup membingungkan, karena tidak memicu kesalahan apa pun; itu hanya diam-diam tidak muncul.
Glenn Maynard
2
Wow, hampir 10 tahun kemudian dan saya masih menyukai solusi ini. Setuju bahwa ini adalah pendekatan yang jauh lebih baik daripada memecah kode Anda menjadi aplikasi yang lebih kecil, yang menurut saya dapat mengarah ke basis kode yang sulit untuk dipikirkan.
Michael Hays
5

Saya tidak mengerti dari banyak kemungkinan masalah yang mungkin Anda miliki. Berikut beberapa kemungkinan dengan jawaban:

  • beberapa model dalam file yang sama

    Masukkan ke dalam file terpisah. Jika ada dependensi, gunakan import untuk menarik model tambahan.

  • logika asing / fungsi utilitas di models.py

    Letakkan logika ekstra ke dalam file terpisah.

  • metode statis untuk memilih beberapa contoh model dari database

    Buat Manajer baru di file terpisah.

  • metode jelas terkait dengan model

    simpan, __unicode__ dan get_absolute_url adalah contohnya.

hughdbrown
sumber