MST

星途 面试题库

面试题:Python的Django RESTful API开发中如何优化性能

阐述在使用Django进行RESTful API开发过程中,针对高并发场景,从数据库查询优化、缓存机制(如Memcached、Redis)的应用、视图函数的优化等方面,说明你会采取哪些措施来提升API的性能,并举例说明。
11.6万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

数据库查询优化

  1. 使用select_related和prefetch_related
    • select_related用于处理外键关系,通过SQL的JOIN操作一次性获取关联对象,减少数据库查询次数。例如,有一个Book模型和Author模型,Book通过外键关联Author
    from myapp.models import Book
    books = Book.objects.select_related('author').all()
    for book in books:
        print(book.author.name)
    
    • prefetch_related适用于多对多或反向一对多关系,它通过多个查询获取数据,然后在Python层面进行合并。比如BookGenre是多对多关系:
    from myapp.models import Book
    books = Book.objects.prefetch_related('genres').all()
    for book in books:
        for genre in book.genres.all():
            print(genre.name)
    
  2. 避免N+1查询问题:在循环中进行数据库查询会导致N+1查询问题(1次查询获取主数据,N次查询获取关联数据)。可以通过上述select_relatedprefetch_related解决,或者在必要时手动进行批量查询。例如,要获取多个Book对象及其对应的Review数量:
    from myapp.models import Book, Review
    book_ids = [1, 2, 3]
    reviews_count = {review.book_id: review.count() for review in Review.objects.filter(book_id__in = book_ids).values('book_id').annotate(count = Count('id'))}
    books = Book.objects.filter(id__in = book_ids)
    for book in books:
        print(f"Book {book.title} has {reviews_count.get(book.id, 0)} reviews")
    
  3. 索引优化
    • 为经常用于过滤、排序和连接的字段添加索引。例如,如果经常根据publication_date字段查询Book
    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length = 200)
        publication_date = models.DateField()
    
        class Meta:
            indexes = [
                models.Index(fields = ['publication_date']),
            ]
    

缓存机制应用

  1. Memcached
    • 安装和配置Memcached后,在Django中可以使用django - cache来集成。例如,缓存一个视图函数的响应:
    from django.views.decorators.cache import cache_page
    
    @cache_page(60 * 15)  # 缓存15分钟
    def my_api_view(request):
        # 视图逻辑
        pass
    
    • 也可以在较低层次使用cache对象来缓存特定数据。比如缓存一个数据库查询结果:
    from django.core.cache import cache
    def get_books():
        key = 'all_books'
        books = cache.get(key)
        if not books:
            books = Book.objects.all()
            cache.set(key, books, 60 * 5)  # 缓存5分钟
        return books
    
  2. Redis
    • 安装redis - py库后,可以在Django中使用Redis作为缓存。例如,使用Redis缓存视图响应:
    from django_redis.decorators import cache_page
    
    @cache_page(60 * 10, cache ='redis_cache')  # 缓存10分钟,使用名为'redis_cache'的缓存配置
    def my_api_view(request):
        # 视图逻辑
        pass
    
    • 利用Redis的高级数据结构进行缓存和数据处理。比如使用Redis的Sorted Set来缓存热门书籍排行榜:
    import redis
    r = redis.Redis(host='localhost', port = 6379, db = 0)
    def update_book_rankings(book_id, score):
        r.zadd('book_rankings', {book_id: score})
    def get_top_books():
        top_book_ids = r.zrevrange('book_rankings', 0, 9)
        return Book.objects.filter(id__in = top_book_ids)
    

视图函数优化

  1. 减少不必要的计算:避免在视图函数中进行复杂且重复的计算。例如,如果某些数据是固定的,可以将其提取到全局变量或者单独的模块中。
    # 假设这是一个固定的配置
    API_VERSION = 'v1'
    
    def my_api_view(request):
        # 视图逻辑
        pass
    
  2. 异步处理:对于一些耗时的操作,可以使用异步任务队列(如Celery)。例如,在API处理用户注册时,发送欢迎邮件可能是耗时操作,可将其异步化:
    • 定义任务:
    from celery import shared_task
    
    @shared_task
    def send_welcome_email(user_email):
        # 发送邮件逻辑
        pass
    
    • 在视图函数中调用任务:
    from django.http import JsonResponse
    from. tasks import send_welcome_email
    
    def register_user(request):
        if request.method == 'POST':
            # 处理用户注册逻辑
            user_email = 'user@example.com'
            send_welcome_email.delay(user_email)
            return JsonResponse({'message': 'User registered successfully'})
    
  3. 使用视图集和路由器:在Django REST framework中,使用视图集和路由器可以简化代码,提高性能。例如:
    from rest_framework.viewsets import ModelViewSet
    from rest_framework.routers import DefaultRouter
    from myapp.models import Book
    from myapp.serializers import BookSerializer
    
    class BookViewSet(ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
    router = DefaultRouter()
    router.register('books', BookViewSet)
    
    这样可以自动生成多个API端点(如列表、详情、创建、更新、删除等),减少重复代码,提高开发效率和性能。