You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Django同步视图转异步时的两类报错问题

Django异步APIView错误修复方案

错误1:SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

问题根源

在异步函数get_available_riders中直接调用了同步的Django ORM操作:

  • Rider.objects.filter()
  • queryset.exists()
  • queryset.first()

这类同步IO操作不能在异步上下文直接执行,必须用asgiref.sync.sync_to_async包裹后调用。而你错误地给异步Firestore的stream()方法套了sync_to_async——实际上riderexpert_db是firestore.AsyncClient,它的stream()本身就是异步方法,不需要额外包裹。


错误2:TypeError: object Response can't be used in 'await' expression

问题根源

在get_available_riders的异常捕获中,直接返回了handle_google_maps_api_error(e)的结果(一个Response对象)。但get_available_riders是异步函数,上层get方法用await调用它时,会尝试等待这个返回值,而Response不是可等待对象,因此触发错误。

正确做法是在get_available_riders中重新抛出异常,让上层get方法统一捕获并处理,而非直接返回Response。


完整修复代码

from asgiref.sync import sync_to_async
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
import firestore
from googlemaps import Client as GoogleMapsClient, ApiError
from django.conf import settings
import logging

logger = logging.getLogger(__name__)

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:
            # 异步Firestore操作,无需sync_to_async
            riders_collection = await riderexpert_db.collection("riders").stream()

            riders_within_radius = []
            for firestore_rider in riders_collection:
                firestore_data = firestore_rider.to_dict()
                email = firestore_data.get("email")

                # 用sync_to_async包裹同步ORM操作,合并exists()与first()判断
                django_rider = await sync_to_async(
                    lambda: Rider.objects.filter(
                        user__email=email,
                        is_available=True,
                        fragile_item_allowed=is_fragile,
                        min_capacity__lte=item_capacity,
                        max_capacity__gte=item_capacity,
                    ).first()
                )()

                if django_rider:
                    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:
                        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:
            # 重新抛出异常,交给上层get方法统一处理
            raise e

关键修改点

  1. 移除Firestore的sync_to_async包裹:异步客户端的stream()方法直接用await调用即可。
  2. 用sync_to_async包裹ORM操作:将Rider.objects.filter().first()用sync_to_async包裹,同时合并exists()判断,减少一次数据库查询。
  3. 调整异常处理逻辑:在get_available_riders中不再直接返回Response,而是重新抛出异常,让上层get方法的捕获逻辑统一处理。

内容的提问来源于stack exchange,提问作者Abdulmujeeb Ahmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 10:08:14