Django中如何返回筛选地址全部交易历史?优化查询代码
房产交易历史查询代码优化方案
问题背景
现有Django查询代码通过列表推导返回符合条件房产的全部交易历史,但列表会一次性加载所有数据到内存,需要优化为无需生成列表即可返回全部交易历史,同时保留原有功能。
优化方案
方案一:生成器替代列表推导(改动最小)
将原代码中返回列表的部分改为生成器表达式,这样不会一次性生成所有元素,而是按需迭代,大幅降低内存占用,调用方的extend操作可正常使用。
修改后返回部分代码:
return ( [ e.id, e.bedrooms, e.type, e.year_built, e.square_feet, e.lot_size, e.location.id, e.location.address, e.location.postal_code, e.location.latitude, e.location.longitude, e.location.city.name if e.location.city else None, e.location.neighbourhood.name if e.location.neighbourhood else None, sh.date, sh.price ] for e in estates for sh in e.sold_histories.all() )
方案二:直接关联查询(性能最优)
通过SoldHistory模型直接关联查询所需字段,使用values_list返回惰性求值的QuerySet,无需加载ORM实例,内存占用极低,查询效率更高。
完整优化后代码:
def filter_model(estate, years=[], exact_match=False, distance_km=None): query_filter = Q(location__postal_code__isnull=False, sold_histories__isnull=False) if distance_km: query_filter &= Q(location__point__distance_lte=( estate.location.point, distance_km)) query_filter &= Q(type=estate.type) query_filter &= Q(square_feet__isnull=False) query_filter &= Q(year_built__isnull=False) if estate.type == 2: address = str(estate.location.address).split('#')[0].strip() query_filter &= Q(location__address__icontains=address) # 获取符合条件的房产ID集合 estate_ids = Estate.objects.filter(query_filter).values_list('id', flat=True).distinct() # 直接查询关联的交易历史,返回所需字段 return SoldHistory.objects.filter( estate_id__in=estate_ids ).select_related( 'estate__location__city', 'estate__location__neighbourhood' ).order_by('-date').values_list( 'estate__id', 'estate__bedrooms', 'estate__type', 'estate__year_built', 'estate__square_feet', 'estate__lot_size', 'estate__location__id', 'estate__location__address', 'estate__location__postal_code', 'estate__location__latitude', 'estate__location__longitude', 'estate__location__city__name', 'estate__location__neighbourhood__name', 'date', 'price' ) else: if len(years) == 2: query_filter &= Q(sold_histories__date__year=years[0]) if exact_match: query_filter &= Q(location__city__province__id=estate.location.city.province.id) else: query_filter &= Q(location__city__id=estate.location.city.id) # 获取符合条件的房产ID集合 estate_ids = Estate.objects.filter(query_filter).filter( sold_histories__date__year=years[1] ).values_list('id', flat=True).distinct() # 查询指定年份的交易历史,返回所需字段 return SoldHistory.objects.filter( estate_id__in=estate_ids, date__year__in=years ).select_related( 'estate__location__city', 'estate__location__neighbourhood' ).values_list( 'estate__id', 'estate__bedrooms', 'estate__type', 'estate__year_built', 'estate__square_feet', 'estate__lot_size', 'estate__location__id', 'estate__location__address', 'estate__location__postal_code', 'estate__location__latitude', 'estate__location__longitude', 'estate__location__city__name', 'estate__location__neighbourhood__name', 'date', 'price' )
说明
- 方案一仅需修改返回部分,保留原有ORM实例逻辑,适合需要后续操作对象的场景。
- 方案二直接从数据库获取目标字段,避免加载冗余数据,性能更优,适合大数据量场景。
- 两种方案返回的结果均可直接用于
estates_by_km.extend(...),无需修改调用逻辑。
内容的提问来源于stack exchange,提问作者user9272398
相关产品推荐
相关产品推荐

