如何给 Django 打猴子补丁?

发布于 2024-11-24 08:45:01 字数 812 浏览 5 评论 0原文

我发现了这篇关于猴子修补 Django 的帖子

from django.contrib.auth.models import User

User.add_to_class('openid', models.CharField(max_length=250,blank=True))

def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username

User.add_to_class("get_user_name",get_user_name)

我明白这并不理想,最好通过单独的模型 ProfileUser 添加字段和函数。

话虽如此,我只想了解这是如何工作的:

  1. 我将猴子修补代码放在哪里?

  2. 代码什么时候运行——只运行一次?每次Python解释器启动一次?每个请求一次?

  3. 大概我仍然需要更改数据库架构。因此,如果我删除表 User 并运行 ./manage.pysyncdbsyncdb 会“知道”新字段已添加到用户?如果不是,我该如何更改架构?

I came upon this post on monkey patching Django:

from django.contrib.auth.models import User

User.add_to_class('openid', models.CharField(max_length=250,blank=True))

def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username

User.add_to_class("get_user_name",get_user_name)

I understand that this isn't ideal and it's better to add fields and functions to User through a separate model Profile.

With that said, I just want to understand how this would work:

  1. Where would I put the monkey patching code?

  2. When is the code run -- just once? once per Python interpreter startup? once per request?

  3. Presumably I'd still need to change the DB schema. So if I dropped the table User and ran ./manage.py syncdb, would syncdb "know" that a new field has been added to User? If not how do I change the schema?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清醇 2024-12-01 08:45:01

将文件 monkey_patching.py 放入任何 应用 中,并将其导入到应用的 __init__.py 文件中。即:

app/monkey_patching.py

#app/monkey_patching.py
from django.contrib.auth.models import User

User.add_to_class('openid', models.CharField(max_length=250,blank=True))

def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username

User.add_to_class("get_user_name",get_user_name)

app/__init__.py

#app/__init__.py
import monkey_patching

put the file monkey_patching.py in any of your apps and import it in app's __init__.py file. ie:

app/monkey_patching.py

#app/monkey_patching.py
from django.contrib.auth.models import User

User.add_to_class('openid', models.CharField(max_length=250,blank=True))

def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username

User.add_to_class("get_user_name",get_user_name)

app/__init__.py

#app/__init__.py
import monkey_patching
烂柯人 2024-12-01 08:45:01

您可以将其放在任何地方,但在设置文件(甚至 urlconf)中经常会看到此类内容的链接。任何可以放置信号的地方也可能是合适的。这段代码确实应该稍微智能一些 - 通常文件会被多次导入,并且您对此无能为力,因此如果您尝试多次运行这样的代码,您可能会遇到问题。

每个 python 进程至少需要执行一次代码。

是的,您需要手动更改数据库。 Syncdb可能不会捕获更改(我没有仔细查看代码),但可能在某些地方可以放置可以工作的代码。

您似乎已经知道这是一件非常非常可怕的事情,并且永远不应该对真正的代码执行此操作,因此我不会详细说明这一点。做这种事情是一种极好的方法,可以在代码中生成很难找到的错误,此外还可能会出现在未来版本的 Django 中无法工作的代码。

此外,它不适用于您应该使用的 South。

You could put it anywhere, but it's common to see this kind of stuff linked in the settings file (or even the urlconf). Anywhere you could put a signal might also be appropriate. This code should really be slightly more intelligent - often files get imported more than once and there's not a lot you can do about it, so you can run into problems if you try to run code like this multiple times.

The code needs to be executed at least once for each python process.

Yes you would need to change the DB by hand. Syncdb probably wouldn't catch the change (I haven't looked closely at the code), but there might be some places you could put the code that would work.

You seem to already know that this is a terrible, horrible thing to do and should never be done for real code, so I won't belabor that point. Doing this kind of thing is a fantastic way to generate really difficult to find bugs in your code, in addition to code that may not work in future versions of Django.

Also, it won't work well with South, which you should be using.

泅渡 2024-12-01 08:45:01

使用 @suhailvs 和 @Paul McMillan 的建议,我在应用程序的根目录中添加了一个 patch.py​​ 文件,并在应用程序的 apps.py 中调用了我的 patched < code>ready 信号:

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = "MyApp"

    def ready(self):
        """
        Called when the app is ready.
        """
        from .patch import patch_func

        patch_func()

AppRegistryNotReady:应用尚未加载。 是由于导入而不是函数调用而发生的,因此它必须位于函数内部。

Using both @suhailvs and @Paul McMillan's suggestions I added a patch.py file to the root of my app, and inside the app's apps.py called my patched in the ready signal:

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = "MyApp"

    def ready(self):
        """
        Called when the app is ready.
        """
        from .patch import patch_func

        patch_func()

The AppRegistryNotReady: Apps aren't loaded yet. happens because of the import, not the function call, so it must be inside the function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文