我正在开发 django 视图来获取可用乘客的列表。我首先在同步上下文中创建,当我测试它时,它按预期工作。我需要它处于异步上下文中,但是当我尝试将 i 转换为异步上下文时,我收到以下错误消息:
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
这是我尝试转换为异步上下文时在异步上下文中的代码,但出现了上面的错误:
riderexpert_db = firestore.AsyncClient(project="riderexpert", database="riderexpert-db")
class GetAvailableRidersView(APIView):
permission_classes = [IsAuthenticated]
SEARCH_RADIUS_METERS = 10
async def get_google_maps_client(self):
"""Initialize and return the asynchronous Google Maps API client."""
return GoogleMapsClient(key=settings.GOOGLE_MAPS_API_KEY)
async def validate_parameters(self, order_location, item_capacity, is_fragile):
"""Validate input parameters."""
try:
item_capacity = float(item_capacity)
is_fragile = str_to_bool(is_fragile)
except (ValueError, TypeError):
return False, "Invalid or missing parameters"
if not all(
[
order_location is not None and isinstance(order_location, str),
item_capacity is not None and isinstance(item_capacity, (int, float)),
is_fragile is not None and isinstance(is_fragile, bool),
]
):
return False, "Invalid or missing parameters"
return True, ""
def handle_google_maps_api_error(self, e):
"""Handle Google Maps API errors."""
return Response(
{"status": "error", "message": f"Google Maps API error: {str(e)}"},
status=400,
)
def handle_internal_error(self, e):
"""Handle internal server errors."""
logger.error(str(e))
return Response(
{"status": "error", "message": "Error processing the request"}, status=500
)
async def get(self, request, *args, **kwargs):
order_location = request.GET.get("origin")
item_capacity = request.GET.get("item_capacity")
is_fragile = request.GET.get("is_fragile")
# Handle Missing or Invalid Parameters
is_valid, validation_message = await self.validate_parameters(
order_location, item_capacity, is_fragile
)
if not is_valid:
return Response(
{"status": "error", "message": validation_message}, status=400
)
try:
# Initialize asynchronous Google Maps API client
gmaps = await self.get_google_maps_client()
# Optimize Database Queries
available_riders = await self.get_available_riders(
gmaps, order_location, item_capacity, is_fragile
)
return Response({"status": "success", "riders": available_riders})
except ApiError as e:
logger.error(f"Google Maps API error: {str(e)}")
return self.handle_google_maps_api_error(e)
except Exception as e:
return self.handle_internal_error(e)
finally:
# Close the asynchronous Firestore client
await riderexpert_db.close()
async def get_available_riders(self, gmaps, order_location, item_capacity, is_fragile):
try:
# Query asynchronous Firestore for available riders locations
riders_collection = await riderexpert_db.collection("riders").stream()
riders_within_radius = []
for firestore_rider in riders_collection:
firestore_data = firestore_rider.to_dict()
# Retrieve rider from Django model using email as identifier
email = firestore_data.get("email")
# Construct queryset to filter riders based on conditions
queryset = Rider.objects.filter(
user__email=email,
is_available=True,
fragile_item_allowed=is_fragile,
min_capacity__lte=item_capacity,
max_capacity__gte=item_capacity,
)
# Check if the queryset is not empty
if queryset.exists():
django_rider = queryset.first()
rider_location = (
firestore_data.get("current_latitude"),
firestore_data.get("current_longitude"),
)
distance_matrix_result = await gmaps.distance_matrix(
origins=order_location,
destinations=rider_location,
mode="driving",
units="metric",
)
distance = distance_matrix_result["rows"][0]["elements"][0][
"distance"
]
duration = distance_matrix_result["rows"][0]["elements"][0][
"duration"
]["text"]
if distance["value"] <= self.SEARCH_RADIUS_METERS * 1000:
# Include both distance and duration in the response
rider_data = {
"rider": RiderSerializer(django_rider).data,
"distance": distance,
"duration": duration,
}
riders_within_radius.append(rider_data)
return riders_within_radius
except ApiError as e:
return self.handle_google_maps_api_error(e)`
所以我使用
sync_to_async from asgiref.sync
对其进行了修改,如下所示:
riderexpert_db = firestore.AsyncClient(project="riderexpert", database="riderexpert-db")
class GetAvailableRidersView(APIView):
permission_classes = [IsAuthenticated]
SEARCH_RADIUS_METERS = 10
async def get_google_maps_client(self):
"""Initialize and return the asynchronous Google Maps API client."""
return GoogleMapsClient(key=settings.GOOGLE_MAPS_API_KEY)
async def validate_parameters(self, order_location, item_capacity, is_fragile):
"""Validate input parameters."""
try:
item_capacity = float(item_capacity)
is_fragile = str_to_bool(is_fragile)
except (ValueError, TypeError):
return False, "Invalid or missing parameters"
if not all(
[
order_location is not None and isinstance(order_location, str),
item_capacity is not None and isinstance(item_capacity, (int, float)),
is_fragile is not None and isinstance(is_fragile, bool),
]
):
return False, "Invalid or missing parameters"
return True, ""
def handle_google_maps_api_error(self, e):
"""Handle Google Maps API errors."""
return Response(
{"status": "error", "message": f"Google Maps API error: {str(e)}"},
status=400,
)
def handle_internal_error(self, e):
"""Handle internal server errors."""
logger.error(str(e))
return Response(
{"status": "error", "message": "Error processing the request"}, status=500
)
async def get(self, request, *args, **kwargs):
order_location = request.GET.get("origin")
item_capacity = request.GET.get("item_capacity")
is_fragile = request.GET.get("is_fragile")
# Handle Missing or Invalid Parameters
is_valid, validation_message = await self.validate_parameters(
order_location, item_capacity, is_fragile
)
if not is_valid:
return Response(
{"status": "error", "message": validation_message}, status=400
)
try:
# Initialize asynchronous Google Maps API client
gmaps = await self.get_google_maps_client()
# Optimize Database Queries
available_riders = await self.get_available_riders(
gmaps, order_location, item_capacity, is_fragile
)
return Response({"status": "success", "riders": available_riders})
except ApiError as e:
logger.error(f"Google Maps API error: {str(e)}")
return self.handle_google_maps_api_error(e)
except Exception as e:
return self.handle_internal_error(e)
finally:
# Close the Firestore client
await riderexpert_db.close()
async def get_available_riders(self, gmaps, order_location, item_capacity, is_fragile):
try:
# Use sync_to_async for Firestore operations
riders_collection = await sync_to_async(
riderexpert_db.collection("riders").stream
)()
riders_within_radius = []
for firestore_rider in riders_collection:
firestore_data = firestore_rider.to_dict()
# Retrieve rider from Django model using email as identifier
email = firestore_data.get("email")
# Construct queryset to filter riders based on conditions
queryset = Rider.objects.filter(
user__email=email,
is_available=True,
fragile_item_allowed=is_fragile,
min_capacity__lte=item_capacity,
max_capacity__gte=item_capacity,
)
# Check if the queryset is not empty
if queryset.exists():
django_rider = queryset.first()
rider_location = (
firestore_data.get("current_latitude"),
firestore_data.get("current_longitude"),
)
distance_matrix_result = await gmaps.distance_matrix(
origins=order_location,
destinations=rider_location,
mode="driving",
units="metric",
)
distance = distance_matrix_result["rows"][0]["elements"][0][
"distance"
]
duration = distance_matrix_result["rows"][0]["elements"][0][
"duration"
]["text"]
if distance["value"] <= self.SEARCH_RADIUS_METERS * 1000:
# Include both distance and duration in the response
rider_data = {
"rider": RiderSerializer(django_rider).data,
"distance": distance,
"duration": duration,
}
riders_within_radius.append(rider_data)
return riders_within_radius
except ApiError as e:
return self.handle_google_maps_api_error(e)
但我仍然收到此错误:
result = await self.awaitable(*args, **kwargs)
TypeError: object Response can't be used in 'await' expression
我该如何解决这个问题?
当您在异步上下文中使用 django 的 orm 功能时,您可以有两个选项(https://docs.djangoproject.com/en/5.0/topics/async/):
在您的代码中,我在这里看到几个示例,您在异步函数中调用 orm ,这可能会导致您收到错误:
queryset = Rider.objects.filter(
user__email=email,
is_available=True,
fragile_item_allowed=is_fragile,
min_capacity__lte=item_capacity,
max_capacity__gte=item_capacity,
)
# Check if the queryset is not empty
if queryset.exists():
django_rider = queryset.first()
rider_location = (
firestore_data.get("current_latitude"),
firestore_data.get("current_longitude"),
)
这肯定会导致错误,因为您在异步函数中调用 orm 同步方法。正确的做法是:
queryset = Rider.objects.filter(
user__email=email,
is_available=True,
fragile_item_allowed=is_fragile,
min_capacity__lte=item_capacity,
max_capacity__gte=item_capacity,
)
# Check if the queryset is not empty
if await queryset.aexists():
django_rider = await queryset.afirst()
rider_location = (
# if firestore_data is queryset
await firestore_data.aget("current_latitude"),
await firestore_data.aget("current_longitude"),
)
这只是您可能收到此错误的一个示例,您应该更正您提供的代码中的所有 orm 方法调用。