Django实现热加载原理(从源码开始分析)

这篇具有很好参考价值的文章主要介绍了Django实现热加载原理(从源码开始分析)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Django实现热加载原理(从源码开始分析)

源码地址

autoreload

代码实现

def run_with_reloader(main_func, *args, **kwargs):
    """
        监听系统的kill命令
        然后启动Django
    """
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
    try:
        """
        这里的判断,一开始 Django_AUTORELOAD_ENV 这个环境变量不能是’true'

        因为他会在restart_with_reloader这里执行一个死循环,然后设置Django_AUTORELOAD_ENV的值是true
        ,然后判断错误代码,如果错误代码不是3就return了,
        如果是3就继续循环
        """
        if os.environ.get(DJANGO_AUTORELOAD_ENV) == "true":
            reloader = get_reloader()
            logger.info(
                "Watching for file changes with %s", reloader.__class__.__name__
            )
            start_django(reloader, main_func, *args, **kwargs)
        else:
            exit_code = restart_with_reloader()
            sys.exit(exit_code)
    except KeyboardInterrupt:
        pass



这里是通过restart_with_reloader这个方法来实现的,首先我们第一次在python manage.py runserver的时候,DJANGO_AUTORELOAD_ENV 这个环境变量的值是None,当我们在执行完restart_with_reloader的时候,这个环境会变成true。

restart_with_reloader方法内部

创建了一个新的环境,然后使用子进程,并把新的环境变量进去,然后获取我们之前命令行的参数。然后判断结束吗等于3,如果不是3,则就直接return

      
 def restart_with_reloader():
    new_environ = {**os.environ, DJANGO_AUTORELOAD_ENV: "true"}
    args = get_child_arguments()
    while True:
        p = subprocess.run(args, env=new_environ, close_fds=False)
        if p.returncode != 3:
            return p.returncode

get_reloader

def get_reloader():
    """Return the most suitable reloader for this environment."""
    try:
        WatchmanReloader.check_availability()
    except WatchmanUnavailable:
        return StatReloader()
    return WatchmanReloader()

可以看到,这里是返回了WatchmanReloader或者StatReloader这个类。我们不看WatchmanReloader这个类,这个类是基于pywatchman 这个库实现的。StatReloader这个类是py自己实现的,其中大致逻辑可以可可以在这里看简单代码这个是我模拟Django来自己写的。

start_django

def start_django(reloader, main_func, *args, **kwargs):
    ensure_echo_on()

    main_func = check_errors(main_func)
    django_main_thread = threading.Thread(
        target=main_func, args=args, kwargs=kwargs, name="django-main-thread"
    )
    django_main_thread.daemon = True
    django_main_thread.start()

    while not reloader.should_stop:
        reloader.run(django_main_thread)

这里就开始跑Django项目了。

这里是以线程的方法开了Django服务,然后判断是否需要停止,如果不停止,则就开始监听

reloader

class BaseReloader:
    def __init__(self):
        self.extra_files = set()
        self.directory_globs = defaultdict(set)
        self._stop_condition = threading.Event()

    def watch_dir(self, path, glob):
        path = Path(path)
        try:
            path = path.absolute()
        except FileNotFoundError:
            logger.debug(
                "Unable to watch directory %s as it cannot be resolved.",
                path,
                exc_info=True,
            )
            return
        logger.debug("Watching dir %s with glob %s.", path, glob)
        self.directory_globs[path].add(glob)

    def watched_files(self, include_globs=True):
        """
        Yield all files that need to be watched, including module files and
        files within globs.
        """
        yield from iter_all_python_module_files()
        yield from self.extra_files
        if include_globs:
            for directory, patterns in self.directory_globs.items():
                for pattern in patterns:
                    yield from directory.glob(pattern)

    def wait_for_apps_ready(self, app_reg, django_main_thread):
        """
        Wait until Django reports that the apps have been loaded. If the given
        thread has terminated before the apps are ready, then a SyntaxError or
        other non-recoverable error has been raised. In that case, stop waiting
        for the apps_ready event and continue processing.

        Return True if the thread is alive and the ready event has been
        triggered, or False if the thread is terminated while waiting for the
        event.
        """
        while django_main_thread.is_alive():
            if app_reg.ready_event.wait(timeout=0.1):
                return True
        else:
            logger.debug("Main Django thread has terminated before apps are ready.")
            return False

    def run(self, django_main_thread):
        logger.debug("Waiting for apps ready_event.")
        self.wait_for_apps_ready(apps, django_main_thread)
        from django.urls import get_resolver

        # Prevent a race condition where URL modules aren't loaded when the
        # reloader starts by accessing the urlconf_module property.
        try:
            get_resolver().urlconf_module
        except Exception:
            # Loading the urlconf can result in errors during development.
            # If this occurs then swallow the error and continue.
            pass
        logger.debug("Apps ready_event triggered. Sending autoreload_started signal.")
        autoreload_started.send(sender=self)
        self.run_loop()

    def run_loop(self):
        ticker = self.tick()
        while not self.should_stop:
            try:
                next(ticker)
            except StopIteration:
                break
        self.stop()

    def tick(self):
        """
        This generator is called in a loop from run_loop. It's important that
        the method takes care of pausing or otherwise waiting for a period of
        time. This split between run_loop() and tick() is to improve the
        testability of the reloader implementations by decoupling the work they
        do from the loop.
        """
        raise NotImplementedError("subclasses must implement tick().")

    @classmethod
    def check_availability(cls):
        raise NotImplementedError("subclasses must implement check_availability().")

    def notify_file_changed(self, path):
        results = file_changed.send(sender=self, file_path=path)
        logger.debug("%s notified as changed. Signal results: %s.", path, results)
        if not any(res[1] for res in results):
            trigger_reload(path)

    # These are primarily used for testing.
    @property
    def should_stop(self):
        return self._stop_condition.is_set()

    def stop(self):
        self._stop_condition.set()


class StatReloader(BaseReloader):
    SLEEP_TIME = 1  # Check for changes once per second.

    def tick(self):
        mtimes = {}
        while True:
            for filepath, mtime in self.snapshot_files():
                old_time = mtimes.get(filepath)
                mtimes[filepath] = mtime
                if old_time is None:
                    logger.debug("File %s first seen with mtime %s", filepath, mtime)
                    continue
                elif mtime > old_time:

                    logger.debug(
                        "File %s previous mtime: %s, current mtime: %s",
                        filepath,
                        old_time,
                        mtime,
                    )
                    print('file is change')
                    self.notify_file_changed(filepath)

            time.sleep(self.SLEEP_TIME)
            yield

    def snapshot_files(self):
        # watched_files may produce duplicate paths if globs overlap.
        seen_files = set()
        for file in self.watched_files():
            if file in seen_files:
                continue
            try:
                mtime = file.stat().st_mtime
            except OSError:
                # This is thrown when the file does not exist.
                continue
            seen_files.add(file)
            yield file, mtime

    @classmethod
    def check_availability(cls):
        return True

StatReloader 这个类是继承了BaseReloader,然后自己实现了tick方法,和check_availability方法。

run在BaseReloader这个类里面,可以看到他是运行了run_look,然后里面运行了tick这个方法。

tick方法是在自子类,也就是StatReloader这个里面实现的,可以看到,他这里就是遍历了监听的文件,然后和上一次修改的时间对比,如果大于上次修改的时间,就触发notify_file_changed方法,这个方法就很简单了,他会把进程杀死,饭后返回3。

总结

Django的热启动,是通过启动了一个子进程,获取到我们在命令行后面的参数,开始运行Django。

监听文件有两个方法,一个是StatReloader(Django内部实现)。WatchmanReloader(微软开源的库)

注意,如果要启用Django的热启动,不能设置Django_AUTORELOAD_ENV值。文章来源地址https://www.toymoban.com/news/detail-759706.html

到了这里,关于Django实现热加载原理(从源码开始分析)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • django如何连接sqlite数据库?

    目录 一、SQLite数据库简介 二、Django连接SQLite数据库 1、配置数据库 2、创建数据库表 三、使用Django ORM操作SQLite数据库 1、定义模型 2、创建对象 3、查询对象 总结 本文将深入探讨如何在Django框架中连接和使用SQLite数据库。我们将介绍SQLite数据库的特点,Django的数据库配置,以

    2024年02月06日
    浏览(54)
  • 分享一个Python Django影片数据爬取与数据分析系统源码

    💕💕 作者:计算机源码社 💕💕 个人简介:本人七年开发经验,擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等,大家有这一块的问题可以一起交流! 💕💕 学习资料、程序开发、技术解答、文档报告 💕💕JavaWeb项目 💕💕微信小程序项目 💕💕Python项目 💕💕

    2024年02月09日
    浏览(44)
  • Django实现注册及登录(附源码)

    目录 一、项目介绍 1、开发环境 2、注册功能介绍 3、登录功能介绍: 4、项目截图  二、数据迁移 1、建立自己的数据库 (1)通过命令行(win+R,输入cmd)进入自己的数据库,如下图所示表示进入成功  (2)创建自己的数据库 (3)配置数据库  (4)创建迁移文件 (5)进行数据

    2024年02月06日
    浏览(31)
  • django sqlite3操作和manage.py功能介绍

     参考链接:https://www.cnblogs.com/csd97/p/8432715.html manage.py 常用命令_python manage.py_追逐梦想的博客-CSDN博客 python django操作sqlite3_django sqlite_浪子仙迹的博客-CSDN博客

    2024年02月12日
    浏览(45)
  • 【从零开始学Django篇001】从创建一个新的Django项目开始

    👑 作 者 主 页 :👉 CSDN 丨 博客园 🏆 学 习 交 流: 👉 在下周周ovoの社区 💎 从零开始 学Django 系列专栏: 👉Django系列专栏 ​ 在这个专栏,大概会从零开始了解到大部分的Django知识点。比如说 Django模板语言,路由系统,视图系统,中间件,AJAX,浏览器的同源策略及使

    2024年02月08日
    浏览(71)
  • 【Django】让SQLite数据库中表名支持重命名的方法

    修改了数据库表名之后,更新数据库时跳错: 意思就是 SQLite 数据库不支持重命名的操作,添加atomic = False即可: Migration 在 py36Libsite-packagesdjangodbmigrationsmigration.py 的位置 将 atomic = True 改成 atomic = False

    2024年02月10日
    浏览(51)
  • 部署Django报错-requires SQLite 3.8.3 or higher

    在部署测试环境时,有需要用到一个python的后端服务,要部署到测试环境中去 心想这不是so easy吗,把本地调试时使用的python版本及Django版本在服务器上对应下载好,然后直接执行命令 不就完事儿了吗,说干就干,立马去服务器布置好python和django的环境,到py项目的根目录下

    2024年02月10日
    浏览(48)
  • SpringBoot源码分析(4)--Environment(下)/配置文件加载原理

    SpringBoot源码分析 SpringBoot源码分析(1)–@SpringBootApplication注解使用和原理/SpringBoot的自动配置原理详解 SpringBoot源码分析(2)–SpringBoot启动源码(万字图文源码debug讲解springboot启动原理) SpringBoot源码分析(3)–Environment简介/prepareEnvironment准备环境(万字图文源码debug分析) 上一篇《

    2024年02月13日
    浏览(40)
  • 毕业设计:基于python微博舆情分析系统+可视化+Django框架 K-means聚类算法(源码)✅

    毕业设计:2023-2024年计算机专业毕业设计选题汇总(建议收藏) 毕业设计:2023-2024年最新最全计算机专业毕设选题推荐汇总 🍅 感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助同学们顺利毕业 。

    2024年01月19日
    浏览(49)
  • Django模板加载与响应

    Django 的模板系统将 Python 代码与 HTML 代码解耦,动态地生成 HTML 页面。Django 项目可以配置一个或多个模板引擎,但是通常使用 Django 的模板系统时,应该首先考虑其内置的后端 DTL(Django Template Language,Django 模板语言。 在 Django 中,模板是可以根据字典数据动态变化的,并且

    2024年02月07日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包