แยก Models.py ออกเป็นหลายไฟล์


91

ฉันกำลังพยายามแยกmodels.pyแอปของฉันออกเป็นหลาย ๆ ไฟล์:

การเดาครั้งแรกของฉันคือทำสิ่งนี้:

myproject/
    settings.py
    manage.py
    urls.py
    __init__.py
    app1/
        views.py
        __init__.py
        models/
            __init__.py
            model1.py
            model2.py
    app2/
        views.py
        __init__.py
        models/
            __init__.py
            model3.py
            model4.py

วิธีนี้ใช้ไม่ได้ผลฉันพบสิ่งนี้แต่ในโซลูชันนี้ฉันยังคงมีปัญหาเมื่อฉันเรียกใช้python manage.py sqlall app1ฉันได้รับสิ่งที่ต้องการ:

BEGIN;
CREATE TABLE "product_product" (
    "id" serial NOT NULL PRIMARY KEY,
    "store_id" integer NOT NULL
)
;
-- The following references should be added but depend on non-existent tables:
-- ALTER TABLE "product_product" ADD CONSTRAINT "store_id_refs_id_3e117eef" FOREIGN KEY     ("store_id") REFERENCES "store_store" ("id") DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "product_product_store_id" ON "product_product" ("store_id");
COMMIT;

ฉันไม่ค่อยแน่ใจเกี่ยวกับเรื่องนี้ แต่ฉันกังวลเกี่ยวกับส่วนนี้ The following references should be added but depend on non-existent tables:

นี่คือไฟล์ model1.py ของฉัน:

from django.db import models

class Store(models.Model):
    class Meta:
        app_label = "store"

นี่คือไฟล์ model3.py ของฉัน:

from django.db import models

from store.models import Store

class Product(models.Model):
    store = models.ForeignKey(Store)
    class Meta:
        app_label = "product"

และเห็นได้ชัดว่าใช้งานได้ แต่ฉันได้รับความคิดเห็นalter tableและถ้าฉันลองสิ่งนี้จะเกิดขึ้น:

class Product(models.Model):
    store = models.ForeignKey('store.Store')
    class Meta:
        app_label = "product"

ดังนั้นฉันควรเรียกใช้การเปลี่ยนแปลงสำหรับการอ้างอิงด้วยตนเองหรือไม่? นี่อาจทำให้ฉันมีปัญหากับทิศใต้?


จะเกิดอะไรขึ้นในรุ่น 3 ถ้าคุณลองfrom app1.models.model1 import Store?
James Khoury

นอกจากนี้คุณอาจต้องการดูstackoverflow.com/questions/5534206/…
James Khoury

คำตอบ:


33

ฉันจะทำสิ่งต่อไปนี้:

myproject/
    ...
    app1/
        views.py
        __init__.py
        models.py
        submodels/
            __init__.py
            model1.py
            model2.py
    app2/
        views.py
        __init__.py
        models.py
        submodels/
            __init__.py
            model3.py
            model4.py

แล้ว

#myproject/app1/models.py:
    from submodels/model1.py import *
    from submodels/model2.py import *

#myproject/app2/models.py:
    from submodels/model3.py import *
    from submodels/model4.py import *

แต่ถ้าคุณไม่มีเหตุผลที่ดีให้ใส่ model1 และ model2 โดยตรงใน app1 / models.py และ model3 และ model4 ใน app2 / models.py

---ส่วนที่สอง---

นี่คือไฟล์ app1 / submodels / model1.py:

from django.db import models
class Store(models.Model):
    class Meta:
        app_label = "store"

ดังนั้นแก้ไขไฟล์ model3.py ของคุณ:

from django.db import models
from app1.models import Store

class Product(models.Model):
    store = models.ForeignKey(Store)
    class Meta:
        app_label = "product"

แก้ไขแล้วในกรณีที่สิ่งนี้เกิดขึ้นอีกครั้งสำหรับใครบางคน: ดู django-schedule สำหรับตัวอย่างของโครงการที่ทำสิ่งนี้ https://github.com/thauber/django-schedule/tree/master/schedule/models https://github.com/thauber/django-schedule/


1
เกี่ยวกับคำตอบนี้ฉันมีปัญหาอีกครั้งเมื่ออยู่ใน models2.py ทำสิ่งที่ชอบfrom product.models import Product: ImportError: No module named models
diegueus9

68
คุณจะทำวิธีนี้เพื่อรักษาหนึ่งคลาสต่อไฟล์
worc

50
"ทำไม" คือความปรารถนาที่จะลดขนาดmodels.pyไฟล์ขนาดใหญ่ ฉันเพิ่งทำสิ่งนี้เมื่อของฉันมีโค้ดมากกว่า 15,000 บรรทัด แม้ว่าการเขียนที่ยอดเยี่ยม กระบวนการนี้ค่อนข้างง่าย ข้อแม้หลักคือคุณต้องจำไว้ว่าให้กำหนด app_label ที่ชัดเจนเนื่องจาก Django ดึงสิ่งนี้ออกจากโมดูลทันทีตามค่าเริ่มต้น
Cerin

1
ลองดูในปี 2016 ส่วนที่สองของโพสต์นี้ยังจำเป็นอยู่ไหม ฉันย้ายชั้นเรียนไปยังไฟล์ที่แยกจากกันเท่านั้นเขียนของฉัน__init__.pyและดูเหมือนว่าทุกอย่างจะทำงานได้ดี ฉันไม่ต้องแก้ไขไฟล์โมเดลของฉัน ฉันสามารถดึงและสร้างวัตถุจากเชลล์และผู้ดูแลระบบ django ฉันลองใช้ django มาประมาณหนึ่งสัปดาห์แล้วดังนั้นฉันจึงสงสัยว่าตอนนี้เวอร์ชันใหม่ล่าสุดอนุญาตให้เกิดขึ้นได้หรือไม่?
วิก

3
@Vic: app_label ในคลาส Meta ไม่จำเป็นอีกต่อไปกับ Django เวอร์ชันใหม่กว่า ดูcode.djangoproject.com/wiki/CookBookSplitModelsToFiles
jrial

149

สำหรับทุกคนบน Django 1.9 ตอนนี้ได้รับการสนับสนุนโดยกรอบงานโดยไม่ต้องกำหนดข้อมูลเมตาคลาส

https://docs.djangoproject.com/en/1.9/topics/db/models/#organizing-models-in-a-package

หมายเหตุ:สำหรับ Django 2 ยังคงเหมือนเดิม

manage.py startappคำสั่งสร้างโครงสร้างแอพลิเคชันที่มีไฟล์ models.py หากคุณมีหลายรุ่นการจัดระเบียบในไฟล์แยกกันอาจเป็นประโยชน์

โดยสร้างแพ็กเกจโมเดล ลบ Models.py และสร้างmyapp/models/ไดเร็กทอรีพร้อม__init__.pyไฟล์และไฟล์เพื่อจัดเก็บโมเดลของคุณ คุณต้องนำเข้าโมเดลใน__init__.pyไฟล์

ดังนั้นในกรณีของคุณสำหรับโครงสร้างเช่น

app1/
    views.py
    __init__.py
    models/
        __init__.py
        model1.py
        model2.py
app2/
    views.py
    __init__.py
    models/
        __init__.py
        model3.py
        model4.py

คุณต้องทำเท่านั้น

#myproject/app1/models/__init__.py:
from .model1 import Model1
from .model2 import Model2

#myproject/app2/models/__init__.py:
from .model3 import Model3
from .model4 import Model4

หมายเหตุเกี่ยวกับการนำเข้าคลาสทั้งหมด:

การนำเข้าแต่ละโมเดลอย่างชัดเจนแทนที่จะใช้from .models import *มีข้อดีคือไม่ทำให้เนมสเปซเกะกะทำให้โค้ดอ่านง่ายขึ้นและทำให้เครื่องมือวิเคราะห์โค้ดมีประโยชน์



7
หมายเหตุ: โดยปกติจะทำงานไม่ถูกต้องเมื่อคุณเริ่มต้นmodels.pyและต้องการย้ายข้อมูลในภายหลัง ในกรณีนี้คุณต้องลบการย้ายข้อมูลและฐานข้อมูลของคุณ: / หรือเพื่อแก้ไขข้อผิดพลาดทั้งหมดในไฟล์การย้ายข้อมูลทั้งหมดด้วยตนเอง
tuergeist

ยังคงตอบได้ดีที่สุด สามารถยืนยันได้ว่ายังใช้งานได้ใน 2.1+
Roys

1
ฉันไม่เห็นปัญหาที่ @tuergeist ชี้ให้เห็นใน Django 3.0 ดูเหมือนจะใช้งานได้ดี
caram

11

ฉันเจอบทช่วยสอนสำหรับสิ่งที่คุณกำลังถามจริงๆคุณสามารถดูได้ที่นี่:

http://paltman.com/breaking-apart-models-in-django/

ประเด็นสำคัญประการหนึ่งที่อาจเกี่ยวข้อง - คุณอาจต้องการใช้ฟิลด์ db_table บนคลาส Meta เพื่อชี้คลาสที่ย้ายกลับไปที่โต๊ะของตนเอง

ฉันสามารถยืนยันได้ว่าวิธีนี้ใช้ได้ผลใน Django 1.3


ลิงค์นั้นให้ 404
Bryan Oakley

1

ขั้นตอนที่ง่ายที่สุด:

  1. สร้างโฟลเดอร์โมเดลในแอพของคุณ (ชื่อโฟลเดอร์ควรเป็นโมเดล )
  2. ลบไฟล์ model.py จากไดเรกทอรีแอพ(สำรองไฟล์ขณะที่คุณลบ)
  3. และหลังจากสร้างไฟล์init. py ในโฟลเดอร์โมเดล
  4. และหลังจากเริ่มต้นไฟล์. py ในการเขียนอย่างง่ายหนึ่งบรรทัด
  5. และหลังจากสร้างไฟล์โมเดลในโฟลเดอร์โมเดลของคุณแล้วชื่อไฟล์โมเดลควรจะเหมือนกับชื่อคลาสถ้าชื่อคลาสเป็น 'พนักงาน' กว่าชื่อไฟล์โมเดลควรเป็น 'พนักงาน.py'
  6. และหลังจากในไฟล์โมเดลกำหนดตารางฐานข้อมูลของคุณเหมือนกับเขียนในไฟล์model.py
  7. บันทึกไว้

รหัสของฉัน: จาก django_adminlte.models. พนักงานนำเข้าพนักงาน

สำหรับ: จากapp_name .models model_file_name_onlyนำเข้าClass_Name_which_define_in_model_file


__init__.py

from django_adminlte.models.employee import Employee

model/employee.py (employee is separate model file)

from django.db import models

class Employee(models.Model):
eid = models.CharField(max_length=20)
ename = models.CharField(max_length=20)
eemail = models.EmailField()
econtact = models.CharField(max_length=15)

class Meta:
    db_table = "employee"
    # app_label = 'django_adminlte'
    
def __str__(self):
    return self.ename

2
นี่คือสิ่งที่เขาพยายามแก้ไข โซลูชันนี้จะทำให้เกิดRuntimeError ModelX doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.ใน django 2.x
radtek

0

ฉันเขียนสคริปต์ที่อาจเป็นประโยชน์

github.com/victorqribeiro/splitDjangoModels

มันแยกรุ่นในแต่ละไฟล์ด้วยการตั้งชื่อและการนำเข้าที่เหมาะสม มันยังสร้างไฟล์ init เพื่อให้คุณสามารถนำเข้าโมเดลทั้งหมดของคุณได้ในครั้งเดียว

แจ้งให้เราทราบหากสิ่งนี้ช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.