Django:动态查询集函数分配性能

Django3: Dynamic queryset function allocation performance

我只是在试验如何 'dynamically allocate queryset functions' 我想知道以后可能会遇到的性能问题。

我的查询集运行良好,但我对它们有点怀疑。

请看我的代码:

settings.py:

...
TODO_PRIORITY = (
     ('LOW', 'Low'),
     ('MEDIUM', 'Medium'),
     ('HIGH', 'High'),
)
...

models.py

from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
from .manager import TodoManager
from django.conf import settings

User = get_user_model()

TODO_PRIORITY = getattr(settings, 'TODO_PRIORITY', None)
assert TODO_PRIORITY is not None, "Your settings file is missing `TODO_PRIORITY` variable"
assert isinstance(TODO_PRIORITY, tuple), "`TODO_PRIORITY` must be a tuple"

# Create your models here.
class Todo(models.Model):
    class Meta:
        ordering = ('start_time',)

    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="todos")
    content = models.TextField(max_length=500, blank=False)

    start_time = models.DateTimeField(default=timezone.now)
    end_time = models.DateTimeField(blank=False)

    priority = models.CharField(max_length=6, choices=TODO_PRIORITY, default="MEDIUM")
    timestamp = models.DateTimeField(auto_now_add=True)

    objects = TodoManager()

    @property
    def todo_id(self):
        return self.id

manager.py

from django.db import models
from django.utils import timezone
from django.conf import settings

now = timezone.now()
today = now.replace(hour=0, minute=0, second=0, microsecond=0)
tomorrow = today + timezone.timedelta(days=1)

TODO_PRIORITY = getattr(settings, 'TODO_PRIORITY', None)
assert TODO_PRIORITY is not None, "Your settings file is missing `TODO_PRIORITY` variable."
assert isinstance(TODO_PRIORITY, tuple), "`TODO_PRIORITY` must be a tuple."

class TodoQueryset(models.query.QuerySet):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for priority in TODO_PRIORITY:
            self.add__fn(priority)

    def add__fn(self, object):
        assert isinstance(object, tuple), '`TODO_PRIORITY` object must be a tuple.'
        fn_name = object[1].lower()

        def fn():
            return self.filter(priority=object[0].upper(), start_time__gte=today)

        setattr(self, fn_name, fn)


class TodoManager(models.Manager):
    _queryset_class = TodoQueryset

UPDATE 0

我注意到 __init__() 运行了多次,我该如何避免?

=> 我四处询问,这似乎是一种正常行为,因为 django 使用 filter() 然后 get()

UPDATE 1

我终于让经理找到了一种自动创建 class 方法的方法,我会 post 一分钟内给出答案

四处寻找后,我意识到每次调用 TodoQuerySet 时都会调用我的 add__fn() 函数,所以我决定将 add__fn() 移到 class 之外,并且从那里添加功能。

manager.py

from django.db import models
from django.utils import timezone
from django.conf import settings

now = timezone.now()
today = now.replace(hour=0, minute=0, second=0, microsecond=0)
tomorrow = today + timezone.timedelta(days=1)

TODO_PRIORITY = getattr(settings, 'TODO_PRIORITY', None)
assert TODO_PRIORITY is not None, "Your settings file is missing `TODO_PRIORITY` variable."
assert isinstance(TODO_PRIORITY, tuple), "`TODO_PRIORITY` must be a tuple."

class TodoQuerySet(models.QuerySet):
     pass

def add__fn(object):
    assert isinstance(object, tuple), '`TODO_PRIORITY` object must be a tuple.'
    fn_name = object[1].lower()

    def fn(self):
            return self.filter(priority=object[0].upper(), start_time__gte=today)

    setattr(TodoQuerySet, fn_name, fn)

for priority in TODO_PRIORITY:
    add__fn(priority)

TodoQueryset = TodoQuerySet

models.py

from .manager import TodoQueryset

class Todo(...):

    objects = TodoQueryset.as_manager()