Django-如何可视化信号并保存替代?

Mil*_*ano 20 python architecture django software-design

随着项目的发展,依存关系和事件链也会不断增长,尤其是在覆盖的save()方法post_savepre_save信号中。

例:

覆盖将A.save创建两个相关的对象A- BC。当C被保存时,post_save信号被调用,做别的事情,等...

如何弄清楚这些事件的下巴?有没有办法可视化(自动生成)这样的链/流?我既没有寻找,ERD也没有任何Class图表。我需要确保在一个地方做一件事情不会影响项目另一侧的事情,所以简单的可视化将是最好的。

编辑

明确地说,我知道检查动态生成的信号几乎是不可能的。我只想检查所有(不是动态生成的)post_savepre_save和重写的save方法并将其可视化,这样我就可以立即看到正在发生的事情以及何时发生的save事情。

Bea*_*own 10

This is not the full solution, but I hope it can be a good starting point. Consider this code:

from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver

class A(models.Model):
    def save(self, *args, **kwargs):
        if not self.pk:
            C.objects.create()

class B(models.Model):
    pass

class C(models.Model):
    b = models.ForeignKey(B, on_delete=models.CASCADE, blank=True)

@receiver(pre_save, sender=C)
def pre_save_c(sender, instance, **kwargs):
    if not instance.pk:
        b = B.objects.create()
        instance.b = b
Run Code Online (Sandbox Code Playgroud)

We can get the dependencies for the app name list using inspect, django get_models(), and signals in this manner:

import inspect
import re
from collections import defaultdict

from django.apps import apps
from django.db.models import signals

RECEIVER_MODELS = re.compile('sender=(\w+)\W')
SAVE_MODELS = re.compile('(\w+).objects.')

project_signals = defaultdict(list)
for signal in vars(signals).values():
    if not isinstance(signal, signals.ModelSignal):
        continue
    for _, receiver in signal.receivers:
        rcode = inspect.getsource(receiver())
        rmodel = RECEIVER_MODELS.findall(rcode)
        if not rmodel:
            continue
        auto_by_signals = [
            '{} auto create -> {}'.format(rmodel[0], cmodel)
            for cmodel in SAVE_MODELS.findall(rcode)
        ]
        project_signals[rmodel[0]].extend(auto_by_signals)

for model in apps.get_models():
    is_self_save = 'save' in model().__class__.__dict__.keys()
    if is_self_save:
        scode = inspect.getsource(model.save)
        model_name = model.__name__
        for cmodel in SAVE_MODELS.findall(scode):
            print('{} auto create -> {}'.format(model_name, cmodel))
            for smodels in project_signals.get(cmodel, []):
                print(smodels)
Run Code Online (Sandbox Code Playgroud)

This gives:

A auto create -> C
C auto create -> B
Run Code Online (Sandbox Code Playgroud)

Updated: change method to found overridden save by the instance class dict.

is_self_save = 'save' in model().__class__.__dict__.keys()
Run Code Online (Sandbox Code Playgroud)


Mat*_*one 5

(太长,无法放入注释,缺少完整的代码)

我现在无法模拟大量代码,但是另一个受马里奥·奥兰迪(Mario Orlandi)的评论启发的有趣解决方案将是某种脚本,该脚本可以扫描整个项目并搜索所有覆盖的保存方法以及保存前和保存后的信号,跟踪创建它们的类/对象。它可能像一系列正则表达式表达式一样简单,这些表达式表达式查找class定义,然后是save内部的任何重写方法。

扫描完所有内容后,您可以使用该引用集合根据类名称创建一个依赖树(或树集),然后对每个树进行拓扑排序。任何连接的组件都将说明依赖关系,您可以可视化或搜索这些树以非常简单自然的方式查看依赖关系。我在django中比较天真,但是看来您可以通过这种方式静态跟踪依赖项,除非这些方法在不同时间在多个地方被覆盖是很普遍的。