2015-10-21 32 views
11

我在不同情況下碰到過這個問題幾次,但我的設置如下:Python/Django:爲什麼在使用它之前導入模塊會阻止循環導入?

我有兩個Django模型文件。一個包含用戶模型和CouponCodes,用戶可以用來註冊課程。這些都在account/models.py文件中。課程和相關的多對多字段位於不同的模型文件course/models.py中。我通常在我的代碼中分別將它們稱爲amod和cmod。

在課程/ models.py我有一個import語句:

from account import models as amod 

class Course(ExtendedModel): 
    stuff = stuff 

我需要導入帳戶/ models.py文件的許多一對多課程與用戶之間的模型/表,該表這裏沒有顯示。到現在爲止還挺好。

在account/models.py文件中,我有CouponCode模型。每個實例都被創建,然後可以在創建後分配給特定的課程對象,以便學生可以使用它來註冊系統中的課程。

class CouponCode(ExtendedModel): 
    assigned_course = UniqueIDForeignKey("course.Course", blank=True, null=True, related_name='assigned_coupon_code_set') 
    ... 
    ... 

    @staticmethod 
    def assign_batch(c, upper_limit): 
     import course.models as cmod # Why is this allowed here? 
     assert isinstance(c, cmod.Course) 

     # Do other stuff here 

靜態方法可以讓我在一門課程的對象和數量,我想分配給它CouponCodes的傳遞,然後它會分配未分配的代碼是當然,接下來的N數。我的問題來自於主張聲明。

我需要從course/models.py中導入Course對象,以確保傳入的對象實際上是Course的一個實例,但如果我在文件頂部執行該操作,則會出現問題,因爲此文件已被導入course/models.py。 (amod被導入到cmod中,然後在amod中我需要導入cmod)。

爲什麼它允許我這樣做,如果我在需要它之前將它導入到方法中,而不是在文件頂部?

回答

8

當一個模塊被導入(以及第一次導入給定進程時),所有頂級語句都會被執行(請記住,import是一個可執行語句)。所以你不能在module1的頂層有import module2語句,而在頂層有import module1的module2 - 它顯然不能工作。

現在,如果在module2中將import module1語句移入某個函數中,則在實際調用該函數之前,該語句將不會執行,因此它不會阻止module1導入module2。

請注意,這仍然被認爲是不好的做法,大多數情況下,循環依賴意味着您應該重構代碼以避免該問題(將兩個模塊提取的部分依賴於第三個模塊,但這兩個模塊都不依賴於其他人依賴或簡單地合併模塊) - 但由於其他限制,某些情況很複雜,因此將此作爲最後解決方案是很好的。

此外,您需要導入模型引用它在ForeignKeyMany2Many場 - 您可以通過一個"appname.ModelName"串,CF https://docs.djangoproject.com/en/1.8/ref/models/fields/#foreignkey

要引用另一個應用程序定義的模型,您可以明確指定 具有完整應用程序標籤的模型。例如,如果上述在其他應用程序中定義的 製造商模式叫 生產,你需要使用:

class Car(models.Model): 
    manufacturer = models.ForeignKey('production.Manufacturer') 

解決圓形進口 依賴兩個應用程序之間時,這種類型的引用可能是有用的。

+0

根據您的經驗,創建外鍵時是否曾經有過使用字符串引用而不是類引用的原因?對我來說,似乎總是這樣做是避免問題的好方法。 – Spartacus

+0

@Spartacus遲到的答案對不起 - 使用字符串引用強制orm做一些額外的查找,並最終導入解析引用,所以你在進程啓動時會有輕微的懲罰。這是否是一個問題留給你的欣賞......但你可以用相反的方式來解決問題:爲什麼在你已經擁有該類的時候使用字符串引用?) –

相關問題