简体   繁体   English

Django:理解 .values() 和 .values_list() 用例

[英]Django: understanding .values() and .values_list() use cases

I'm having trouble understanding under what circumstances are .values() or .values_list() better than just using Model instances?我无法理解在什么情况下 .values() 或 .values_list() 比仅使用 Model 实例更好?

I think the following are all equivalent:我认为以下都是等价的:

results = SomeModel.objects.all()
for result in results:
    print(result.some_field)

results = SomeModel.objects.all().values()
for result in results:
    print(result['some_field'])

results = SomeModel.objects.all().values_list()
for some_field, another_field in results:
    print(some_field)

obviously these are stupid examples, could anyone point out a good reason for using .values() / .values_list() over just using Model instances directly?显然这些都是愚蠢的例子,谁能指出使用 .values() / .values_list() 而不是直接使用 Model 实例的充分理由?

edit :编辑 :

I did some simple profiling, using a noddy model that contained 2 CharField(max_length=100) Iterating over just 500 instances to copy 'first' to another variable, taking the average of 200 runs I got following results:我做了一些简单的分析,使用包含 2 CharField(max_length=100) 的 noddy 模型迭代仅 500 个实例以将“第一个”复制到另一个变量,取 200 次运行的平均值,我得到以下结果:

 Test.objects.all()                                  time: 0.010061947107315063
 Test.objects.all().values('first')                  time: 0.00578328013420105
 Test.objects.all().values_list('first')             time: 0.005257354974746704
 Test.objects.all().values_list('first', flat=True)  time: 0.0052023959159851075
 Test.objects.all().only('first')                    time: 0.011166254281997681

So the answer is definitively : performance!所以答案是肯定的:性能! (mostly, see knbk answer below) (大多数情况下,请参阅下面的 knbk 答案)

.values() and .values_list() translate to a GROUP BY query. .values().values_list()转换为GROUP BY查询。 This means that rows with duplicate values will be grouped into a single value.这意味着具有重复值的行将被分组为一个值。 So say you have a model People the following data:所以说你有一个模型People以下数据:

+----+---------+-----+
| id |  name   | age |
+----+---------+-----+
|  1 | Alice   |  23 |
|  2 | Bob     |  42 |
|  3 | Bob     |  23 |
|  4 | Charlie |  30 |
+----+---------+-----+

Then People.objects.values_list('name', flat=True) will return 3 rows: ['Alice', 'Bob', 'Charlie'] .然后People.objects.values_list('name', flat=True)将返回 3 行: ['Alice', 'Bob', 'Charlie'] The rows with name 'Bob' are grouped into a single value.名称为'Bob'的行被分组为一个值。 People.objects.all() will return 4 rows. People.objects.all()将返回 4 行。

This is especially useful when doing annotations.这在进行注释时特别有用。 You can do eg People.objects.values_list('name', Sum('age')) , and it will return the following results:您可以执行例如People.objects.values_list('name', Sum('age')) ,它将返回以下结果:

+---------+---------+
|  name   | age_sum |
+---------+---------+
| Alice   |      23 |
| Bob     |      65 |
| Charlie |      30 |
+---------+---------+

As you can see, the ages of both Bob's have been summed, and are returned in a single row.如您所见,两个 Bob 的年龄已经相加,并在一行中返回。 This is different from distinct() , which only applies after the annotations.这与distinct()不同,后者仅适用于注释之后。

Performance is just a side-effect, albeit a very useful one.性能只是一个副作用,尽管它非常有用。

values() and values_list() are both intended as optimizations for a specific use case: retrieving a subset of data without the overhead of creating a model instance. values() 和 values_list() 都旨在针对特定用例进行优化:检索数据子集而无需创建模型实例的开销。 Good explanation is given in the Django Documentation . Django 文档中给出了很好的解释。

I use "values_list()" to create a Custom Dropdown Single Select Box for Django Admin as shown below:我使用“values_list()”Django Admin创建一个自定义下拉单选框,如下所示:

# "admin.py"

from django.contrib import admin
from django import forms
from .models import Favourite, Food, Fruit, Vegetable

class FoodForm(forms.ModelForm):
                                # Here
    FRUITS = Fruit.objects.all().values_list('id', 'name')
    fruits = forms.ChoiceField(choices=FRUITS)

                                        # Here
    VEGETABLES = Vegetable.objects.all().values_list('id', 'name')
    vegetables = forms.ChoiceField(choices=VEGETABLES)
    
class FoodInline(admin.TabularInline):
    model = Food
    form = FoodForm

@admin.register(Favourite)
class FavouriteAdmin(admin.ModelAdmin):
    inlines = [FoodInline]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM