我正在使用 drf 創建一個端點來列出用戶。在測驗代??碼時,我意識到它呼叫了 7 個查詢。
models.py:(我認為使用django的User模型會達到同樣的效果)
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_("The Email must be set"))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)
if extra_fields.get("is_staff") is not True:
raise ValueError(_("Superuser must have is_staff=True."))
if extra_fields.get("is_superuser") is not True:
raise ValueError(_("Superuser must have is_superuser=True."))
return self.create_user(email, password, **extra_fields)
class BaseUser(AbstractUser):
email = models.EmailField(_("email address"), unique=True)
id_number = models.CharField(max_length=MID_LENGTH)
username = None
USERNAME_FIELD = "email"
REQUIRED_FIELDS = [email]
objects = CustomUserManager()
def __str__(self) -> str:
return self.email
序列化程式.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.BaseUser
fields = "__all__"
api.py:
class ListUserView(ListAPIView):
permission_classes = [IsAdminUser]
queryset = models.BaseUser.objects.all().order_by("id")
serializer_class = serializers.UserSerializer
測驗.py:
from . import models
from django.db import connection
from django.test.utils import CaptureQueriesContext
from django.urls import reverse
from django_seed import Seed
from rest_framework.test import APIClient, APITestCase
seeder = Seed.seeder()
CREDENTIALS = ["[email protected]", "12345678"]
class UserViewsTest(APITestCase):
def setUp(self) -> None:
# Create user and login
self.user = models.BaseUser.objects.create(email=CREDENTIALS[0], is_staff=True)
self.user.set_password(CREDENTIALS[1])
self.user.save()
self.assertTrue(
self.client.login(email=CREDENTIALS[0], password=CREDENTIALS[1])
)
# Seed users
seeder.add_entity(models.BaseUser, 1)
seeder.execute()
def tearDown(self) -> None:
self.client.logout()
def test_list_users(self):
"""
7 queries:
1. Logged in user session
2. 2 of each of:
i. 1 query for base user
ii. 1 query for base user's group
iii. 1 query for base user's permission
"""
with CaptureQueriesContext(connection) as queries:
response = self.client.get(reverse("accounts-list-users"))
self.assertEqual(200, response.status_code)
self.assertIsNotNone(response.content)
print(queries.captured_queries)
它進行 7 次查詢的原因可能是什么?我知道一個查詢是針對會話內容的。此外,有沒有辦法可以減少查詢的數量?
下面是 print(queries.captured_queries) 的輸出:
[
{
"sql": "SELECT `django_session`.`session_key`, `django_session`.`session_data`, `django_session`.`expire_date` FROM `django_session` WHERE (`django_session`.`expire_date` > '2022-02-22 08:41:16.815976' AND `django_session`.`session_key` = 'hebjioxebumhz0y1mumtafwk3lfoj81h') LIMIT 21",
"time": "0.001",
},
{
"sql": "SELECT `accounts_baseuser`.`id`, `accounts_baseuser`.`password`, `accounts_baseuser`.`last_login`, `accounts_baseuser`.`is_superuser`, `accounts_baseuser`.`first_name`, `accounts_baseuser`.`last_name`, `accounts_baseuser`.`is_staff`, `accounts_baseuser`.`is_active`, `accounts_baseuser`.`date_joined`, `accounts_baseuser`.`email`, `accounts_baseuser`.`id_number` FROM `accounts_baseuser` WHERE `accounts_baseuser`.`id` = 1 LIMIT 21",
"time": "0.000",
},
{
"sql": "SELECT `accounts_baseuser`.`id`, `accounts_baseuser`.`password`, `accounts_baseuser`.`last_login`, `accounts_baseuser`.`is_superuser`, `accounts_baseuser`.`first_name`, `accounts_baseuser`.`last_name`, `accounts_baseuser`.`is_staff`, `accounts_baseuser`.`is_active`, `accounts_baseuser`.`date_joined`, `accounts_baseuser`.`email`, `accounts_baseuser`.`id_number` FROM `accounts_baseuser` ORDER BY `accounts_baseuser`.`id` ASC",
"time": "0.000",
},
{
"sql": "SELECT `auth_group`.`id`, `auth_group`.`name` FROM `auth_group` INNER JOIN `accounts_baseuser_groups` ON (`auth_group`.`id` = `accounts_baseuser_groups`.`group_id`) WHERE `accounts_baseuser_groups`.`baseuser_id` = 1",
"time": "0.001",
},
{
"sql": "SELECT `auth_permission`.`id`, `auth_permission`.`name`, `auth_permission`.`content_type_id`, `auth_permission`.`codename` FROM `auth_permission` INNER JOIN `accounts_baseuser_user_permissions` ON (`auth_permission`.`id` = `accounts_baseuser_user_permissions`.`permission_id`) INNER JOIN `django_content_type` ON (`auth_permission`.`content_type_id` = `django_content_type`.`id`) WHERE `accounts_baseuser_user_permissions`.`baseuser_id` = 1 ORDER BY `django_content_type`.`app_label` ASC, `django_content_type`.`model` ASC, `auth_permission`.`codename` ASC",
"time": "0.001",
},
{
"sql": "SELECT `auth_group`.`id`, `auth_group`.`name` FROM `auth_group` INNER JOIN `accounts_baseuser_groups` ON (`auth_group`.`id` = `accounts_baseuser_groups`.`group_id`) WHERE `accounts_baseuser_groups`.`baseuser_id` = 2",
"time": "0.000",
},
{
"sql": "SELECT `auth_permission`.`id`, `auth_permission`.`name`, `auth_permission`.`content_type_id`, `auth_permission`.`codename` FROM `auth_permission` INNER JOIN `accounts_baseuser_user_permissions` ON (`auth_permission`.`id` = `accounts_baseuser_user_permissions`.`permission_id`) INNER JOIN `django_content_type` ON (`auth_permission`.`content_type_id` = `django_content_type`.`id`) WHERE `accounts_baseuser_user_permissions`.`baseuser_id` = 2 ORDER BY `django_content_type`.`app_label` ASC, `django_content_type`.`model` ASC, `auth_permission`.`codename` ASC",
"time": "0.000",
},
]
uj5u.com熱心網友回復:
7個查詢:
- 獲取會話。為避免此查詢,您可以使用例如session
cached_dbbackend。 - 從資料庫中獲取登錄用戶的詳細資訊。這也可以通過從快取(或者可能是會話物件本身)獲取資料的不同會話后端來避免(但您必須小心例如快取失效)。
- 列出用戶。由于您要列出用戶,因此這是意料之中的。
- 獲取用戶 1 的分配組。
- 獲取用戶 1 的分配權限。
- 獲取用戶 2 的分配組。
- 獲取用戶 2 的分配權限。
可以通過以下方式避免從 4 到 7 的查詢:
- 從序列化器中洗掉資料。(您當前正在使用
fields = "__all__".)如果您的序列化程式不序列化權限和組,它們也不會被獲取。 - 在視圖集的查詢集中添加一個合適的
.prefetch_related()(因為這些是 M2M)子句,所以這些是在 2 個查詢中完成的,而不是 2N 個查詢。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/434133.html
標籤:Python django 测试 django-rest-framework
下一篇:VBA訪問自動編號失敗
