如何优化Djiango-ORM

如何优化Djiango-ORM

1.工具推荐

请摒弃简单粗暴的print

大家经常在windows中安装pycharm开发,项目部署在虚拟机中,在本地浏览器中查看效果,这种方式在调试上会有点麻烦,django-debug-toolbar 的出现,就解决了这个问题

使用步骤:

  1. 使用 pip install django-debug-toolbar安装django-debug-toolbar。(注意Django版本和debug_toolbar的版本兼容问题)
  2. 在项目根目录下创建好static目录,并在在setting中添加APPS
INSTALLED_APPS = [
    'debug_toolbar',
     ]
STATIC_URL = '/static/'
  1. 在URL中添加如下配置
from django.conf import settings```python
from django.urls import include, path```python
from django.conf.urls import include, url  # For django versions before 2.0```python
if settings.DEBUG:
    import debug_toolbar
    urlpatterns = [
        path('__debug__/', include(debug_toolbar.urls)),
        ] + urlpatterns
    # For django versions before 2.0:
    # url(r'^__debug__/', include(debug_toolbar.urls)),
  1. 在setting中添加 Middleware
MIDDLEWARE = [
    # ...
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    # ...
    ]

如果你的Django版本是2.0以前的版本则:

MIDDLEWARE_CLASSES = [
     # ...
    'debug_toolbar.middleware.DebugToolbarMiddleware',
     # ...
    ]
  1. 在settings.py中添加INTERNAL_IPS = (‘127.0.0.1’,),(从哪些ip访问站点,显示debug_toolbar)
INTERNAL_IPS = ('127.0.0.1',)
  1. 请确保setting中DEBUG选项为true
  2. 添加DEBUG_TOOLBAR_PANELS选项
DEBUG_TOOLBAR_PANELS = [
    'debug_toolbar.panels.versions.VersionsPanel',
    'debug_toolbar.panels.timer.TimerPanel',
    'debug_toolbar.panels.settings.SettingsPanel',
    'debug_toolbar.panels.headers.HeadersPanel',
    'debug_toolbar.panels.request.RequestPanel',
    'debug_toolbar.panels.sql.SQLPanel',
    'debug_toolbar.panels.staticfiles.StaticFilesPanel',
    'debug_toolbar.panels.templates.TemplatesPanel',
    'debug_toolbar.panels.cache.CachePanel',
    'debug_toolbar.panels.signals.SignalsPanel',
    'debug_toolbar.panels.logging.LoggingPanel',
    'debug_toolbar.panels.redirects.RedirectsPanel',
]

最后
在这里插入图片描述

2.什么是懒加载

由于 Django 的 ORM 是惰性的,它只取出当前查询所需响应最小的数据。存在于外键和多对多关系时,ORM不检索关联对象的数据如果你调用关联对象时Django的ORM会再次查询数据库。因此如果用户量大的时候访问网站时势必会对数据库造成巨大压力!

有句话说的是:只要你在序列化中使用嵌套关系,你就在拿你的性能开玩笑!

问题根源

cmd:python manage.py shell #进入shell调试 或者ipython
from authorization.models import User
users=User.objects.all()
print(users.query) #打印sql语句 ,第一次查询user

user=users[0]
user_menu=user.menu.all()
print(user_menu.query)  #第二次查询menu

3.预加载

如何解决Django-ORM中的多次查询呢?其实Django已经提供了方法—预加载

  1. select_related —预加载单个关联对象(ForeignKey)
  2. prefetch_related —预加载多个关联对象(ManyToManyField)

具体列子如下:

class CustomerSerializer(serializers.ModelSerializer): 
    orders = OrderSerializer(many=True, read_only=True)
    
    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related('orders')
        return queryset

调用例子:

customer_qs = Customers.objects.all()
customer_qs = CustomerSerializer.setup_eager_loading(customer_qs)  # Set up eager loading to avoid N+1 selects
post_data = CustomerSerializer(customer_qs, many=True).data

具体的代码实例

from django.db import models
from django.contrib.auth.models import User
from django.db import models
from django.contrib.auth.models import User

    class Event(models.Model):
        creator = models.ForeignKey(User)
        name = models.TextField()
        event_date = models.DateTimeField()

    class Attendee(models.Model):
        events = models.ManyToManyField(Event, related_name='attendees')
        organization = models.ForeignKey(Organization, null=True)

    class Organization(models.Model):
        name = models.TextField()

预加载代码如下:

class EventSerializer(serializers.ModelSerializer):
        creator = serializers.StringRelatedField()
        attendees = AttendeeSerializer(many=True)
        unaffiliated_attendees = AttendeeSerializer(many=True)
        
        @staticmethod
        def setup_eager_loading(queryset):
            """ Perform necessary eager loading of data. """
            # select_related for "to-one" relationships
            queryset = queryset.select_related('creator')

            # prefetch_related for "to-many" relationships
            queryset = queryset.prefetch_related(
            'attendees',
            'attendees__organization')

            # Prefetch for subsets of relationships
            queryset = queryset.prefetch_related(
                Prefetch('unaffiliated_attendees',
                queryset=Attendee.objects.filter(organization__isnull=True))
                )
            return queryset

总结:以上是django中实现预加载功能,总之:任何时候你通过 ORM 查询嵌套关系时,你都应该考虑建立适合的预加载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值