gpt4 book ai didi

python - Django queryset 结果对于测试是错误的

转载 作者:太空宇宙 更新时间:2023-11-04 00:21:00 26 4
gpt4 key购买 nike

我的模型是:

class AndroidOffer(models.Model):
name = models.CharField(max_length=128, db_index=True)
# ...
countries = models.ManyToManyField(Country)

以及以下代码(我跳过了之前的过滤):

active_offers = active_offers.filter(countries__in=[country])

它生成这个 SQL 查询:

SELECT "offers_androidoffer"."id", "offers_androidoffer"."name", "offers_androidoffer"."title", "offers_androidoffer"."is_for_android", "offers_androidoffer"."is_for_ios", "offers_androidoffer"."url", "offers_androidoffer"."icon", "offers_androidoffer"."cost", "offers_androidoffer"."quantity", "offers_androidoffer"."hourly_completions", "offers_androidoffer"."is_active", "offers_androidoffer"."description", "offers_androidoffer"."comment", "offers_androidoffer"."priority", "offers_androidoffer"."offer_type", "offers_androidoffer"."package_name", "offers_androidoffer"."is_search_install", "offers_androidoffer"."search_query", "offers_androidoffer"."launches" FROM "offers_androidoffer" INNER JOIN "offers_androidoffer_platform_versions" ON ("offers_androidoffer"."id" = "offers_androidoffer_platform_versions"."androidoffer_id") INNER JOIN "offers_androidoffer_countries" ON ("offers_androidoffer"."id" = "offers_androidoffer_countries"."androidoffer_id") WHERE ("offers_androidoffer"."is_active" = True AND "offers_androidoffer"."quantity" > 0 AND NOT ("offers_androidoffer"."id" IN (SELECT U0."offer_id" FROM "offers_androidofferstate" U0 WHERE (U0."device_id" = 1 AND (U0."state" = 3 OR U0."state" = 4)))) AND NOT ("offers_androidoffer"."package_name" IN (SELECT V0."package_name" FROM "applications_app" V0 INNER JOIN "applications_deviceapp" V1 ON (V0."id" = V1."app_id") WHERE (V1."device_id" IN (SELECT U0."device_id" FROM "users_userdevice" U0 WHERE U0."user_id" = 2) AND NOT (V0."package_name" IN (SELECT U2."package_name" FROM "offers_androidofferstate" U0 INNER JOIN "offers_androidoffer" U2 ON (U0."offer_id" = U2."id") WHERE (U0."device_id" = 1 AND (U0."state" = 0 OR U0."state" = 1 OR U0."state" = 2))))))) AND "offers_androidoffer_platform_versions"."platformversion_id" IN (14) AND "offers_androidoffer_countries"."country_id" IN (6252001)) ORDER BY "offers_androidoffer"."priority" DESC;

如果我在 Postgresql 控制台中运行此查询,它将返回 0 行,但是 active_offers 有 4 个结果(表中的所有行),就像我删除 AND "offers_androidoffer_countries"一样。"country_id"IN (6252001) 语句。

我从测试(APITestCase.client -> DRF view -> filter queryset)运行这段代码。 Django 版本为 2.0.2。

为什么它会忽略国家/地区过滤?

UPD. 我刚刚检查了简单的 TestCase(测试 -> 过滤器查询集)测试,它返回了正确的行数。因此,问题仅存在于 DRF 测试中。

UPD 2. 工作不正常的测试用例:

class AndroidOffersListTests(APITestCase):
fixtures = [
'geo/fixtures/cities.json',
'offers/fixtures/users.json',
'offers/fixtures/devices.json',
'offers/fixtures/geo.json',
'offers/fixtures/apps.json',
'offers/fixtures/offers.json',
]

def test_list_offers_1(self):
user_device = UserDevice.objects.get(pk=1)

token = AndroidOffersListTests.get_token_for_device(user_device)
self.client.credentials(HTTP_AUTHORIZATION='Token {}'.format(token))

url = AndroidOffersListTests.get_url(user_device)
response = self.client.get(url)

self.assertEqual(status.HTTP_200_OK, response.status_code)
self.assertEqual(0, len(response.data)) # result is 4

查看代码:

class AndroidOffersView(ListAPIView):
model = AndroidOffer
serializer_class = AndroidOffersSerializer
permission_classes = (IsAuthenticated,)

def get_queryset(self):
device = UserDevice.get_from_request(self.request)
if device is None:
raise PermissionDenied()

return AndroidOffer.get_offers_for_device(device)

get_offers_for_device:

@staticmethod
def get_offers_for_device(user_device):
active_offers = AndroidOffer.get_active_offers()

# Filter completed
completed_states = AndroidOfferState.get_completed_for_device(user_device)
completed_offers_ids = completed_states.values_list('offer__pk', flat=True)

active_offers = active_offers.exclude(pk__in=completed_offers_ids)

# Filter apps already installed on the user's devices
apps = user_device.user.apps

# Remove packages that are in progress
in_progress_states = AndroidOfferState.get_in_progress_for_device(user_device)
in_progress_packages = in_progress_states.values_list('offer__package_name', flat=True)
apps = apps.exclude(package_name__in=in_progress_packages)

packages = apps.values_list('package_name', flat=True)

active_offers = active_offers.exclude(package_name__in=packages)

# Filter by platform version
active_offers = active_offers.filter(platform_versions__in=[user_device.device.version])

# Filter by country
country = user_device.last_geo_record.country
if country is not None:
active_offers = active_offers.filter(countries__in=[country])

return active_offers

正常工作的测试用例:

class AndroidOffersListTests(TestCase):
fixtures = [
'geo/fixtures/cities.json',
'offers/fixtures/users.json',
'offers/fixtures/devices.json',
'offers/fixtures/geo.json',
'offers/fixtures/apps.json',
'offers/fixtures/offers.json',
]

def test_list_offers_1(self):
user_device = UserDevice.objects.get(pk=1)

offers = AndroidOffer.get_offers_for_device(user_device)

self.assertEqual(0, offers.count()) # 0 — thats ok

更新 3:当我在浏览器中运行相同的请求时,它工作正常:

enter image description here

最佳答案

您说此回复不正确:

self.assertEqual(0, len(response.data)) # result is 4

但您还说此 JSON 响应正确:

{
"count": 0,
"next": null,
"previous": null,
"results": []
}

您在这里使用的是分页 API4 的长度取决于反序列化 json 中存在的键数:

>>> len(json.loads('{"count": 0, "next": null, "previous": null, "results": []}'))
4

请注意,您不需要自己实际调用 json.loads,DRF 框架已经在准备响应时为您处理了这个问题 - 即 response.data已经是一个命令了。

在“工作正常的测试用例”中,您直接处理查询集:

self.assertEqual(0, offers.count()) # 0 — thats ok
^
|____ here you go to the database, no serializer!

如果您想从分页的 JSON api 检查结果的数量,那么您需要向下钻取该页面:

len_results = len(response.data['results'])

对于预期返回 0 个结果的测试,这就足够了。但请注意 - 如果您曾经进行过预期生成的结果多于页面大小(在设置中配置)的测试,您可能还需要检查 countnext值。您必须向后续页面发出额外请求才能收集所有结果。

关于python - Django queryset 结果对于测试是错误的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49120686/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com