减少django中的db查询

Dav*_*542 6 django django-templates django-models django-views

我有一个视图,搜索电影信用数据库,并转换和返回结果,如此 -

# From the following results:
Avatar - James Cameron - director
Avatar - James Cameron - writer
Avatar - James Cameron - editor
Avatar - Julie Jones - writer
Crash - John Smith - director

# ...display in the template as:
Avatar - James Cameron (director, writer, editor)
Avatar - Julie Jones (writer)
Crash - John Smith (director)
Run Code Online (Sandbox Code Playgroud)

但是,当我进行此转换时,print connection.queries我正在访问数据库大约100次.这是我目前拥有的 -

# in models
class VideoCredit(models.Model):
    video = models.ForeignKey(VideoInfo)

    # if the credit is a current user, FK to his profile,
    profile = models.ForeignKey('UserProfile', blank=True, null=True)
    # else, just add his name
    name = models.CharField(max_length=100, blank=True)
    # normalize name for easier searching / pulling of name
    normalized_name = models.CharField(max_length=100)

    position = models.ForeignKey(Position)
    timestamp = models.DateTimeField(auto_now_add=True)
    actor_role = models.CharField(max_length=50, blank=True)    

class VideoInfo(models.Model):
    title = models.CharField(max_length=256, blank=True)
    uploaded_by = models.ForeignKey('UserProfile')
    ...
Run Code Online (Sandbox Code Playgroud)

class Position(models.Model):position = models.CharField(max_length = 100)ordering = models.IntegerField(max_length = 3)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
        ...
Run Code Online (Sandbox Code Playgroud)

在我看来,我正在建立一个三元组的列表,(name, video, [list_of_positions])以显示学分 -

    credit_set = VideoCredit.objects.filter(***depends on a previous function***)
    list_of_credit_tuples = []
    checklist = [] # I am creating a 'checklist' to see whether to append the positions
                   # list of create a new tuple entry
    for credit in credit_set:
        if credit.profile:  # check to see if the credit has an associated profile
            name = credit.profile    
        else:
            name = credit.normalized_name
        if (credit.normalized_name, credit.video) in checklist:
            list_of_keys = [(name, video) for name, video, positions in list_of_credit_tuples]
            index = list_of_keys.index((name, credit.video))
            list_of_credit_tuples[index][2].append(credit.position)
        else:
            list_of_credit_tuples.append((name, credit.video, [credit.position]))
            checklist.append((credit.normalized_name, credit.video))
    ...
Run Code Online (Sandbox Code Playgroud)

最后,在我的模板中显示学分(注意:如果学分有个人资料,请提供指向用户个人资料的链接) -

{% for name, video, positions in list_of_credit_tuples %}
<p>{% if name.full_name %}
    <a href="{% url profile_main user_id=name.id %}">{{name.full_name}}</a>
    {% else %}
    {{name}}
    {% endif %}
    <a href="{% url videoplayer video_id=video.id %}">{{video}}</a>
    ({% for position in positions %}{% ifchanged %}{{position}}{% endifchanged %}{% if not forloop.last %}, {% endif %}{% endfor %})
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

此视图为何以及在何处创建了如此多的数据库查询?如何以及以何种方式使这个视图功能更有效/更好?谢谢.

Joh*_*ohn 15

您将需要查看select_related()(https://docs.djangoproject.com/en/1.3/ref/models/querysets/#select-related)以解决查询泄漏问题.如果你提前知道你将要查看外键相关模型的数据,那么你需要添加select_related.更好的是,如果你知道它只是几个外国钥匙,你只能添加你需要的.

任何时候你看到django运行的查询数量超出了你的预期,select_related几乎总是正确的答案

  • 除此之外,如果您知道您的数据库没有快速变化,那么缓存就是您的朋友.我有一个网站,作者只在每两周发布一次,但是当他这样做时会因为关系而导致各种页面发生变化.我们只是缓存了所有的废话,一旦我们重新计算了令人讨厌的页面,该网站就会过得很快. (2认同)
  • 我无法看到查询,所以也许我忽略了其他触发查询泄漏的内容.我建议使用django-debug-toolbar,这样你就可以很好地了解实际运行的查询次数和次数.寻找模式(几乎相同的查询被运行多次) (2认同)