จะรีโหลดโมดูลใน django shell ได้อย่างไร?


92

ฉันทำงานกับ Django และใช้ Django shell ตลอดเวลา ส่วนที่น่ารำคาญคือในขณะที่เซิร์ฟเวอร์ Django รีโหลดเมื่อมีการเปลี่ยนแปลงโค้ด แต่เชลล์ไม่ทำดังนั้นทุกครั้งที่ฉันทำการเปลี่ยนแปลงวิธีที่ฉันกำลังทดสอบฉันต้องออกจากเชลล์และรีสตาร์ทนำเข้าโมดูลทั้งหมดที่ฉัน จำเป็นต้องเริ่มต้นตัวแปรทั้งหมดที่ฉันต้องการเป็นต้นแม้ว่าประวัติของ iPython จะบันทึกการพิมพ์จำนวนมาก แต่ก็ยังคงเป็นความเจ็บปวด มีวิธีทำให้ django shell reload อัตโนมัติแบบเดียวกับที่ django development server ทำหรือไม่?

ฉันรู้เกี่ยวกับการโหลดซ้ำ () แต่ฉันนำเข้าโมเดลจำนวนมากและโดยทั่วไปใช้from app.models import *ไวยากรณ์ดังนั้นการโหลดซ้ำ () จึงไม่ช่วยได้มากนัก


2
คุณควรอัปเดตคำถามนี้เพื่อทำเครื่องหมายคำตอบ "django-extensions" ว่าถูกต้อง
woodardj

1
จนกว่ามันจะใช้งานได้จริงสำหรับฉัน ฉันติดตั้งส่วนขยายแล้วและไม่มีการรีโหลดโค้ดของฉันโดยอัตโนมัติและฉันไม่เห็นการกล่าวถึงการโหลดซ้ำอัตโนมัติในเอกสาร shell_plus ดูเหมือนว่าจะมีตัวโหลดซ้ำในคำสั่ง runerver_plus แต่นั่นไม่ใช่สิ่งที่ฉันกำลังมองหา
Mad Wombat

คำตอบ:


38

ฉันขอแนะนำให้ใช้โครงการ django-extensions ตามที่ระบุไว้ข้างต้นโดย dongweiming แต่แทนที่จะใช้แค่คำสั่งจัดการ 'shell_plus' ให้ใช้:

manage.py shell_plus --notebook

เพื่อเปิดสมุดบันทึก IPython บนเว็บเบราว์เซอร์ของคุณ เขียนรหัสของคุณที่นั่นในเซลล์การนำเข้าของคุณ ฯลฯ และเรียกใช้

เมื่อคุณเปลี่ยนโมดูลของคุณเพียงคลิกรายการเมนูสมุดบันทึก 'Kernel-> Restart'

เอาล่ะตอนนี้โค้ดของคุณกำลังใช้โมดูลที่แก้ไขแล้ว


32
"แค่ใช้สมุดบันทึก python" ไม่ใช่คำตอบสำหรับคำถามของ OP
J__

1
วิธีนี้แม้ว่าจะไม่อัตโนมัติเหมือน% autoreload แต่ก็ทำงานได้อย่างน่าเชื่อถือกว่าการโหลดอัตโนมัติ การรีสตาร์ทเคอร์เนลรับประกันว่าเซลล์ทั้งหมดในโน้ตบุ๊กจะได้รับโมดูลที่โหลดซ้ำอย่างสมบูรณ์ นอกจากนี้คุณสามารถรีสตาร์ทและเรียกใช้เซลล์ทั้งหมดได้หากคุณเลือก
Anton I.Sipos

76

ผมขอแนะนำให้ใช้ IPython ขยาย autoreload

./manage.py shell

In [1]: %load_ext autoreload
In [2]: %autoreload 2

และจากนี้โมดูลที่นำเข้าทั้งหมดจะได้รับการรีเฟรชก่อนทำการประเมิน

In [3]: from x import print_something
In [4]: print_something()
Out[4]: 'Something'

 # Do changes in print_something method in x.py file.

In [5]: print_something()
Out[5]: 'Something else'

ใช้งานได้เช่นกันหากมีการนำเข้าก่อน%load_ext autoreloadคำสั่ง

./manage.py shell
In [1]: from x import print_something
In [2]: print_something()
Out[2]: 'Something'

 # Do changes in print_something method in x.py file.

In [3]: %load_ext autoreload
In [4]: %autoreload 2
In [5]: print_something()
Out[5]: 'Something else'

นอกจากนี้ยังสามารถป้องกันการนำเข้าบางรายการจากการรีเฟรชด้วย%aimportคำสั่งและ 3 กลยุทธ์การโหลดอัตโนมัติ:

โหลดอัตโนมัติ%

  • โหลดโมดูลทั้งหมดใหม่ (ยกเว้นที่ไม่รวมโดย% aimport) โดยอัตโนมัติทันที

% autoreload 0

  • ปิดใช้งานการโหลดซ้ำอัตโนมัติ

% การโหลดอัตโนมัติ 1

  • โหลดโมดูลทั้งหมดที่นำเข้าด้วย% aimport ทุกครั้งก่อนที่จะรันโค้ด Python ที่พิมพ์

% autoreload 2

  • โหลดโมดูลทั้งหมดซ้ำ (ยกเว้นที่ยกเว้นโดย% aimport) ทุกครั้งก่อนที่จะรันโค้ด Python ที่พิมพ์

Aimport%

  • แสดงรายการโมดูลที่จะนำเข้าโดยอัตโนมัติหรือไม่ต้องนำเข้า

Aimport foo

  • นำเข้าโมดูล 'foo' และทำเครื่องหมายว่าโหลดอัตโนมัติสำหรับ% autoreload 1

เป้าหมายพอร์ต - ฟู

  • ทำเครื่องหมายโมดูล 'foo' เพื่อไม่ให้โหลดอัตโนมัติ

โดยทั่วไปสิ่งนี้ใช้ได้ดีสำหรับการใช้งานของฉัน แต่มีข้อแม้บางประการ:

  • การแทนที่อ็อบเจ็กต์โค้ดไม่ประสบความสำเร็จเสมอไป: การเปลี่ยน @property ในคลาสเป็นวิธีการธรรมดาหรือวิธีการเป็นตัวแปรสมาชิกอาจทำให้เกิดปัญหาได้ (แต่ในอ็อบเจ็กต์เก่าเท่านั้น)
  • ฟังก์ชันที่ถูกลบออก (เช่นผ่านการแพทช์ลิง) จากโมดูลก่อนที่จะโหลดซ้ำจะไม่ได้รับการอัปเกรด
  • ไม่สามารถโหลดโมดูลส่วนขยาย C ซ้ำได้ดังนั้นจึงไม่สามารถโหลดอัตโนมัติได้

3
ในกรณีที่คุณใช้ django /manage.py shell_plus... ถ้าคุณพิมพ์%load_ext autoreloadแล้ว%autoreload 2โมเดลจะถูกโหลดใหม่โดยอัตโนมัติ
ฟิวชั่น

น่าอัศจรรย์คุณทำให้วันของฉัน
Shamsul Arefin Sajib

โปรดทราบว่าคุณต้องติดตั้ง ipython สำหรับสิ่งนี้อย่างชัดเจน ดูเช่นstackoverflow.com/a/47170195/50899
Rabarberski

จะใส่% autoreload นี้ไว้ที่ไหน ไม่ชัดเจนจากคำตอบ
IceFire

40

วิธีแก้ปัญหาของฉันคือฉันเขียนโค้ดและบันทึกลงในไฟล์จากนั้นใช้:

python Manage.py เชลล์ <test.py

ดังนั้นฉันจึงสามารถทำการเปลี่ยนแปลงบันทึกและเรียกใช้คำสั่งนั้นอีกครั้งจนกว่าฉันจะแก้ไขสิ่งที่ฉันพยายามแก้ไข


2
สวยและเรียบง่าย หนึ่งโน้ตเพิ่มexit()ที่ด้านล่างของไฟล์ py เพื่อออกจาก Django shell ในแบบที่สะอาดกว่า ขอบคุณ.
Marc

โซลูชันที่เรียบง่ายและสวยงาม ทำได้ดีมาก
nikoskip

38

ดูคำสั่ง shell_plus manage.py ให้โดยDjango ส่วนขยายโครงการ มันจะโหลดไฟล์โมเดลทั้งหมดของคุณเมื่อเริ่มต้นเชลล์ และโหลดการแก้ไขใด ๆ ของคุณโดยอัตโนมัติ แต่ไม่จำเป็นต้องออกคุณสามารถโทรไปที่นั่นได้โดยตรง


41
ฉันใช้ shell_plus และโมเดลของฉันไม่ได้ทำการรีโหลดอัตโนมัติฉันขาดอะไรไปหรือเปล่า?
Diego Ponciano

31
shell_plus ไม่รีโหลดโมเดลดังนั้นจึงไม่ตอบคำถาม
aljabear

5
ตามที่กล่าวไว้ว่า shell_plus ไม่โหลดโมเดลซ้ำ
zenperttu

2
บางทีฉันอาจจะขาดอะไรไป แต่ shell_plus ไม่ได้รีโหลดอะไรให้ฉัน มันโหลดทุกรุ่นเมื่อเริ่มต้นซึ่งสะดวก แต่ก็นั่นแหละ
Mad Wombat

14
shell_plus สามารถโหลดโมดูลใหม่โดยใช้โมดูลโหลดอัตโนมัติ พิมพ์ '% load_ext autoreload' และ '% autoreload 2' - ดูipython.org/ipython-doc/3/config/extensions/autoreload.html
bbrame

25

ดูเหมือนว่าฉันทามติทั่วไปในหัวข้อนี้คือ python reload () นั้นแย่และไม่มีวิธีที่ดีในการทำเช่นนี้


ไม่ถูกต้อง คำตอบของ @ dongweiming ข้างต้นเป็นทางออกและควรได้รับการยอมรับว่าเป็นคำตอบที่ดีที่สุด
Joseph Sheedy

3
หลายความคิดเห็นเกี่ยวกับคำตอบของเขาบอกว่า shell_plus ไม่รีโหลดโมเดล
Mad Wombat

1
ฉันเพิ่งทดสอบด้วยตัวเองและไม่โหลดซ้ำ นอกจากนี้รหัสที่ไม่ใช่รุ่นที่ฉันนำเข้าด้วยมือล่ะ
Mad Wombat

คลาสในแอพที่ฉันใช้อยู่ตอนนี้โหลดใหม่ได้อย่างยอดเยี่ยม (Python 3.4.3, Django 1.9b1, django-extensions 1.5.9) รวมถึงโมดูลที่ไม่ใช่ django-model ธรรมดาและคลาสที่อยู่ภายใน เป็นเวลา 5 ปีแล้วที่คำตอบนี้เกิดขึ้นและมีการพัฒนามากมาย
Joseph Sheedy

1
ฉันได้ลองในการตั้งค่าเมื่อ 40 นาทีที่แล้วและ shell_plus ไม่โหลดอะไรให้ฉันซ้ำ Django 1.7.10, python 3.4.3, django-extensions 1.5.9
Mad Wombat

6

ทางออกของฉันสำหรับความไม่สะดวกนี้มีดังนี้ ฉันใช้ IPython

$ ./manage.py shell
> import myapp.models as mdls   # 'mdls' or whatever you want, but short...
> mdls.SomeModel.objects.get(pk=100)
> # At this point save some changes in the model
> reload(mdls)
> mdls.SomeModel.objects.get(pk=100)

สำหรับPython 3.xต้องนำเข้า 'reload' โดยใช้:

from importlib import reload

หวังว่าจะช่วยได้ แน่นอนว่ามีวัตถุประสงค์เพื่อการดีบัก

ไชโย


5

Reload () ไม่ทำงานใน Django shell หากไม่มีเทคนิคบางอย่าง คุณสามารถตรวจสอบหัวข้อนี้ได้และคำตอบของฉันโดยเฉพาะ:

คุณจะโหลดโมดูลโมเดล Django ซ้ำโดยใช้ล่ามโต้ตอบผ่าน "Manage.py shell" ได้อย่างไร


4

ใช้shell_plusกับการกำหนดค่า ipython สิ่งนี้จะเปิดใช้งานautoreloadก่อนที่ shell_plus จะนำเข้าสิ่งใด ๆ โดยอัตโนมัติ

pip install django-extensions
pip install ipython
ipython profile create

แก้ไขโปรไฟล์ ipython ของคุณ ( ~/.ipython/profile_default/ipython_config.py):

c.InteractiveShellApp.exec_lines = ['%autoreload 2']
c.InteractiveShellApp.extensions = ['autoreload']

เปิดเปลือกโปรดทราบว่าคุณไม่จำเป็นต้องรวม--ipython:

python manage.py shell_plus

ตอนนี้สิ่งที่กำหนดไว้ในSHELL_PLUS_PRE_IMPORTSหรือSHELL_PLUS_POST_IMPORTS( docs ) จะโหลดอัตโนมัติ!

โปรดทราบว่าหากเชลล์ของคุณอยู่ที่ดีบักเกอร์ (เช่นpdb.set_trace()) เมื่อคุณบันทึกไฟล์อาจรบกวนการโหลดซ้ำ


2
ขอบคุณสำหรับคำตอบ คุณอาจสังเกตว่าฉันถามมันในปี 2010 ฉันดีใจที่รู้ว่าหลังจากแปดปีการโหลดอัตโนมัติในที่สุดก็ใช้งานได้ใน shell_plus :)
Mad Wombat


1

การใช้คำตอบ 2 ข้อรวมกันฉันได้แนวทางง่ายๆเพียงบรรทัดเดียว

คุณสามารถรัน django shell ด้วย -c ซึ่งจะรันคำสั่งที่คุณส่งผ่านอย่างไรก็ตามมันจะออกทันทีหลังจากรันโค้ด

เคล็ดลับคือการตั้งค่าสิ่งที่คุณต้องการเรียกใช้ code.interact (local = local ()) จากนั้นเริ่มเชลล์ใหม่จากภายในรหัสที่คุณส่งผ่าน แบบนี้:

python manage.py shell -c 'import uuid;test="mytestvar";import code;code.interact(local=locals())'

สำหรับฉันฉันแค่ต้องการวิธีการตรวจสอบของห้องสมุดที่สมบูรณ์ เพียงไม่กี่บรรทัด:

python manage.py shell -c 'import code;from rich import pretty;pretty.install();from rich import inspect;code.interact(local=locals())'

ในที่สุดเชอร์รี่ด้านบนก็เป็นนามแฝง

alias djshell='python manage.py shell -c "import code;from rich import pretty;pretty.install();from rich import inspect;code.interact(local=locals())"'

ตอนนี้ถ้าฉันเริ่มต้นเชลล์ของฉันและพูดว่าต้องการตรวจสอบคลาสฟอร์มฉันจะได้ผลลัพธ์ที่สวยงามนี้: ป้อนคำอธิบายภาพที่นี่


0

ไม่ใช่สิ่งที่คุณต้องการ แต่ตอนนี้ฉันมักจะสร้างคำสั่งการจัดการด้วยตนเองสำหรับการทดสอบและเล่นซอกับสิ่งต่างๆ

ในคำสั่งคุณสามารถตั้งค่ากลุ่มคนในท้องถิ่นตามที่คุณต้องการและหลังจากนั้นก็วางลงในเชลล์แบบโต้ตอบ

import code

class Command(BaseCommand):
  def handle(self, *args, **kwargs):
     foo = 'bar'
     code.interact(local=locals())

ไม่ต้องโหลดซ้ำ แต่เป็นวิธีที่ง่ายและน่ารำคาญน้อยกว่าในการทดสอบการทำงานของ django แบบโต้ตอบ

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