37769-vm/fix_view.py
2026-05-30 08:01:02 +00:00

128 lines
5.3 KiB
Python

def door_visits(request):
"""
Manage door knocking visits. Groups unvisited targeted voters by household.
Optimized to handle large datasets more efficiently.
"""
selected_tenant_id = request.session.get("tenant_id")
if not selected_tenant_id:
messages.warning(request, "Please select a campaign first.")
return redirect("index")
tenant = get_object_or_404(Tenant, id=selected_tenant_id)
city_filter = request.GET.get("city", "").strip()
district_filter = request.GET.get('district', '').strip()
neighborhood_filter = request.GET.get('neighborhood', '').strip()
address_filter = request.GET.get('address', '').strip()
voters = Voter.objects.filter(tenant=tenant, is_inactive=False, door_visit=False, target_door_visit=True)
if city_filter:
voters = voters.filter(city__icontains=city_filter)
if district_filter:
voters = voters.filter(district=district_filter)
if neighborhood_filter:
voters = voters.filter(neighborhood__icontains=neighborhood_filter)
if address_filter:
voters = voters.filter(Q(address__icontains=address_filter) | Q(address_street__icontains=address_filter))
# Optimization: Use iterator and lighter data structure
# We only fetch needed fields. Compound index helps here.
voters_iterator = voters.values(
'id', 'first_name', 'last_name', 'address_street', 'city', 'state',
'zip_code', 'neighborhood', 'district', 'latitude', 'longitude', 'phone'
).iterator(chunk_size=2000)
households_dict = {}
for v in voters_iterator:
street = (v['address_street'] or "").strip()
city = (v['city'] or "").strip()
state = (v['state'] or "").strip()
zip_code = (v['zip_code'] or "").strip()
key = (street.lower(), city.lower(), state.lower(), zip_code.lower())
if key not in households_dict:
street_number = ""
street_name = street
match_street = re.match(r'^(\d+)\s+(.*)$', street)
if match_street:
street_number = match_street.group(1)
street_name = match_street.group(2)
try:
street_number_sort = int(street_number)
except (ValueError, TypeError):
street_number_sort = 0
households_dict[key] = {
'address_street': street,
'city': city,
'state': state,
'zip_code': zip_code,
'neighborhood': (v['neighborhood'] or "").strip(),
'district': (v['district'] or "").strip(),
'latitude': float(v['latitude']) if v['latitude'] else None,
'longitude': float(v['longitude']) if v['longitude'] else None,
'street_name_sort': street_name.lower(),
'street_number_sort': street_number_sort,
'target_voters': [],
'voters_json': []
}
else:
if not households_dict[key]['neighborhood'] and v['neighborhood']:
households_dict[key]['neighborhood'] = v['neighborhood'].strip()
if not households_dict[key]['district'] and v['district']:
households_dict[key]['district'] = v['district'].strip()
households_dict[key]['target_voters'].append(v)
phone_display = format_phone_number(v['phone']) if v['phone'] else "<No Phone>"
households_dict[key]['voters_json'].append({'id': v['id'], 'name': f"{v['first_name']} {v['last_name']} - {phone_display}" })
households_list = list(households_dict.values())
del households_dict # Free memory
households_list.sort(key=lambda x: (
not bool(x['neighborhood']),
(x['neighborhood'] or '').lower(),
x['street_name_sort'],
x['street_number_sort']
))
# Optimization: Map data should only be for visible results or limited
# We still keep the limit of 3000 for map
map_data = []
# Always try to show up to 3000 markers instead of showing 0 if count > 3000
for h in households_list[:3000]:
if h['latitude'] and h['longitude']:
map_data.append({
'lat': h['latitude'],
'lng': h['longitude'],
'address_street': h['address_street'],
'city': h['city'],
'state': h['state'],
'zip_code': h['zip_code'],
'address': f"{h['address_street']}, {h['city']}",
'voters': ", ".join([f"{v['first_name']} {v['last_name']}" for v in h['target_voters']])
})
for h in households_list:
h['voters_json_str'] = json.dumps(h['voters_json'])
paginator = Paginator(households_list, 50)
page_number = request.GET.get('page')
households_page = paginator.get_page(page_number)
context = {
'selected_tenant': tenant,
'households': households_page,
'district_filter': district_filter,
'neighborhood_filter': neighborhood_filter,
'address_filter': address_filter,
'city_filter': city_filter,
'map_data_json': json.dumps(map_data),
'map_limit_reached': len(households_list) > 3000,
'GOOGLE_MAPS_API_KEY': getattr(settings, 'GOOGLE_MAPS_API_KEY', ''),
}
return render(request, 'core/door_visits.html', context)