Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 页面加载非常慢-如何正确优化?_Python_Django_Django Models_Django Database_Sql Optimization - Fatal编程技术网

Python 页面加载非常慢-如何正确优化?

Python 页面加载非常慢-如何正确优化?,python,django,django-models,django-database,sql-optimization,Python,Django,Django Models,Django Database,Sql Optimization,我正在写一个大页面,上面有不同的产品统计数据。我在那里使用多个图表、表格等。例如,加载页面需要5秒钟 这是一个非常简化的模型。py 编辑 class Product(models.Model): user = models.ForeignKey(User, null=False, blank=False, related_name='products') name = models.CharField(max_length=200) def get_occurences

我正在写一个大页面,上面有不同的产品统计数据。我在那里使用多个图表、表格等。例如,加载页面需要5秒钟

这是一个非常简化的模型。py

编辑

class Product(models.Model):
    user = models.ForeignKey(User, null=False, blank=False, related_name='products')
    name = models.CharField(max_length=200)

    def get_occurences(self):
        return self.occurences.prefetch_related("scans__price__currency")

    def get_occurences_count(self):
        return self.occurences.all().count()

    def get_all_scans(self):
        return [item for sublist in [x.scans.all() for x in self.get_occurences()] for item in sublist]

    def get_all_valid_scans(self):
        return [item for sublist in [x.get_valid_scans() for x in self.get_occurences()] for item in sublist]

    def get_last_scans(self):
        scans = []
        for occ in self.get_occurences():
            scan = occ.get_last_scan()
            if scan:
                scans.append(scan)
        return scans

   # @property
    #def last_scan_time(self):
        #scans = sorted([x for x in self.get_last_scans() if x.datetime],key = lambda x: x.datetime, reverse=True)
        #Scan.objects.filter(occurence__product=self,price__amount__isnull=False)
        #return str(scans[0].datetime)

    def get_last_min_scan(self):

        sorted_last_scans = [x for x in self.get_last_scans() if x.valid]
        sorted_last_scans.sort(key=lambda x: x.price.eur_price)
        return sorted_last_scans[0] if sorted_last_scans else None

    def get_last_min_price(self):
        last_scan = self.get_last_min_scan()
        if last_scan:
            return last_scan.price.eur_price
        return None

    def get_active_occurences(self):
        return self.get_occurences().filter(active=True)
例如,
occurrencestable
包含此行:

last_scan_time = tables.columns.TemplateColumn("""{{ record.get_last_scan.datetime }}""",accessor='get_last_scan.datetime', verbose_name='Last scan time')
因此,对于每一行,必须执行对调用上次扫描的数据库的查询。更好的方法是预加载所有
Scan
对象

产品

class Product(models.Model):
    user = models.ForeignKey(User, null=False, blank=False, related_name='products')
    name = models.CharField(max_length=200)

    def get_occurences(self):
        return self.occurences.prefetch_related("scans__price__currency")

    def get_occurences_count(self):
        return self.occurences.all().count()

    def get_all_scans(self):
        return [item for sublist in [x.scans.all() for x in self.get_occurences()] for item in sublist]

    def get_all_valid_scans(self):
        return [item for sublist in [x.get_valid_scans() for x in self.get_occurences()] for item in sublist]

    def get_last_scans(self):
        scans = []
        for occ in self.get_occurences():
            scan = occ.get_last_scan()
            if scan:
                scans.append(scan)
        return scans

   # @property
    #def last_scan_time(self):
        #scans = sorted([x for x in self.get_last_scans() if x.datetime],key = lambda x: x.datetime, reverse=True)
        #Scan.objects.filter(occurence__product=self,price__amount__isnull=False)
        #return str(scans[0].datetime)

    def get_last_min_scan(self):

        sorted_last_scans = [x for x in self.get_last_scans() if x.valid]
        sorted_last_scans.sort(key=lambda x: x.price.eur_price)
        return sorted_last_scans[0] if sorted_last_scans else None

    def get_last_min_price(self):
        last_scan = self.get_last_min_scan()
        if last_scan:
            return last_scan.price.eur_price
        return None

    def get_active_occurences(self):
        return self.get_occurences().filter(active=True)
发生次数

class Occurence(models.Model):
    product = models.ForeignKey(Product, related_name='occurences', on_delete=models.CASCADE)

    _last_scan = models.OneToOneField('Scan',null=True,blank=True,related_name='+')


    currency = models.ForeignKey('Currency',related_name='occurences')

    def get_last_scan(self):
        try:
            last = self.scans.select_related("price__amount").order_by('datetime').last()
        except:
            last = None
        return last

    def get_last_valid_scan(self):
        try:
            last = self.scans.exclude(price__isnull=True).order_by('-datetime').first()
        except:
            last = None
        return last

    def get_second_last_valid_scan(self):
        scans = self.scans.exclude(price__isnull=True).order_by('-datetime').select_related("price")
        if scans.count()>=2:
            return scans[1]
        return None

    def get_valid_scans(self):
        return self.scans.all().exclude(price__isnull=True)

    def get_min_scan(self):
        scan = self.get_valid_scans().order_by('price__amount').first()
        if scan:
            return scan
        return None

    """ STATS METHODS """

    def stats_get_difference_for_two_last_scans(self):
        second_last_valid_scan = self.get_second_last_valid_scan()
        if second_last_valid_scan:
            difference_in_percent = math_ops.round_eur(decimal.Decimal(-1 * (100 - self.get_last_valid_scan().price.eur_price / second_last_valid_scan.price.eur_price * 100), 2))
        else:
            difference_in_percent = decimal.Decimal(0)
        return {'percent':difference_in_percent,
                'xml_tag':'<two_last_scans_difference_in_percent>',
                'xml_close_tag':'</two_last_scans_difference_in_percent>',
                'label':'Last scans diff'}

    def stats_get_min_price(self):
        scan = self.get_min_scan()
        if scan:
            price = scan.price.eur_price
        else:
            price = None
        return {'price': price,
                'xml_tag': '<min_price>',
                'xml_close_tag': '</min_price>',
                'label': 'Min'}

    def stats_get_avg_price(self):
        prices = [x.price for x in self.scans.all() if x.price]
        if prices:
            price = math_ops.round_eur(decimal.Decimal(sum([x.eur_price for x in prices]) / len(prices), 2))
        else:
            price = None

        preferred_currency = self.product.user.userprofile.preferred_currency

        if preferred_currency:
            if preferred_currency.shortcut == 'czk':
                amount = Exchange.eur_to_czk(price)
                pref_currency_string = '{} CZK'.format(amount)
                pref_currency_amount = amount
            else:
                amount = price
                pref_currency_string = u'{} €'.format(amount)
                pref_currency_amount = amount
        else:
            if self.currency.shortcut == 'czk':
                amount = Exchange.eur_to_czk(price)
                pref_currency_string = '{} CZK'.format(amount)
                pref_currency_amount = amount
            else:
                amount = price
                pref_currency_string = u'{} €'.format(amount)
                pref_currency_amount = amount


        return {'price': price,
                'pref_currency_string':pref_currency_string,
                'pref_currency_amount':pref_currency_amount,
                'xml_tag': '<average_price>',
                'xml_close_tag': '</average_price>',
                'label': 'AVG'}
class Price(models.Model):
    currency = models.ForeignKey('Currency',related_name='prices')
    amount = models.DecimalField(max_digits=10,decimal_places=2)


    def __unicode__(self):
        return u'{} {}'.format(self.amount,self.currency)

    def to_eur(self):
        if self.currency.shortcut=='eur':
            return self.amount
        elif self.currency.shortcut=='czk':
            return Exchange.objects.first().czk_to_eur(self.amount)

    def to_czk(self):
        if self.currency.shortcut == 'czk':
            return self.amount
        elif self.currency.shortcut == 'eur':
            return Exchange.objects.first().eur_to_czk(self.amount)

    @property
    def eur_price(self):
        if self.currency.shortcut=='eur':
            return self.amount
        elif self.currency.shortcut=='czk':
            return self.to_eur()

    @property
    def czk_price(self):
        cents = decimal.Decimal('01')
        if self.currency.shortcut == 'czk':
            return (self.amount).quantize(cents, decimal.ROUND_HALF_UP)
        elif self.currency.shortcut == 'eur':
            return self.to_czk()

    @property
    def pref_currency_amount(self):
        pref_currency = self.scan.occurence.product.user.userprofile.preferred_currency
        if pref_currency:
            if pref_currency.shortcut == 'czk':
                return self.czk_price
            else: return self.eur_price
        return self.amount

    @property
    def pref_currency_string(self):
        pref_currency = self.scan.occurence.product.user.userprofile.preferred_currency
        # return pref_currency.shortcut
        if pref_currency:
            if pref_currency.shortcut.lower() == 'czk':
                return u'{} {}'.format(self.czk_price, pref_currency.shortcut)
            else:
                return u'{} {}'.format(self.eur_price, pref_currency.special_sign)
        return u'{} {}'.format(self.amount,self.currency.special_sign)


    def get_price(self,currency):
        if currency=='eur':
            return self.eur_price
        elif currency=='czk':
            return self.czk_price

    def get_exchanged_price_string(self):
        if self.currency.shortcut=='czk':
            return u'{} {}'.format(Exchange.czk_to_eur(self.amount),u'€')
        else:
            return u'{} {}'.format(Exchange.eur_to_czk(self.amount),'CZK')

    def get_original_price_string(self):
        if self.currency.shortcut=='czk':
            return u'{} {}'.format(self.amount,u'€')
        else:
            return u'{} {}'.format(Exchange.eur_to_czk(self.amount),'CZK')
例如,根据
django调试工具栏
,渲染表
发生次数
几乎需要2秒钟。我正在尝试使用
select_related
prefetch_related
对其进行优化,但速度仍然很慢

这是因为我调用的不同方法具有相同的查询,并且这些查询被多次调用

class OccurencesTable(tables.Table):
    site = tables.columns.TemplateColumn("""<a href="{{ record.url }}">{{ record.site.name }}</a>""",accessor='site.name', verbose_name=u'Site')
    avg_price = tables.columns.TemplateColumn("""{{ record.stats_get_avg_price.pref_currency_string }}""",accessor='stats_get_avg_price.price', verbose_name='AVG price')
    last_scan_price = tables.columns.TemplateColumn("""{{ record.get_last_scan.price.pref_currency_string }} """,accessor='get_last_scan.price.amount', verbose_name='Last scan price')
    last_scan_time = tables.columns.TemplateColumn("""{{ record.get_last_scan.datetime }}""",accessor='get_last_scan.datetime', verbose_name='Last scan time')
    difference = tables.columns.TemplateColumn("""{% load static %}{% with diff=record.stats_get_difference_for_two_last_scans.percent %}
                {% if diff > 0 %}+{% endif %}{{ diff }} % <img style="height: 15px" src="{% if diff < 0 %}{% static "img/icons/arrow-trend-minus.png" %}{% elif diff == 0 %}{% static "img/icons/arrow-trend-normal.png" %}{% else %}{% static "img/icons/arrow-trend-plus.png" %}{% endif %}">
                {% endwith %}""",verbose_name='Difference')

    class Meta:
        model = Occurence
        fields = ('id', 'site', 'last_scan_time','last_scan_price', 'difference',  'avg_price')
        attrs = {'id': 'id_occurences_table',
                 'class': 'table', }
类发生稳定(tables.Table):
site=tables.columns.TemplateColumn(“”),accessor='site.name',verbose\u name=u'site')
avg_price=tables.columns.TemplateColumn(“{{record.stats_get_avg_price.pref_currency_string}}”,访问器='stats_get_avg_price.price',详细名称='avg price')
last_scan_price=tables.columns.TemplateColumn(“{{record.get_last_scan.price.pref_currency_string}}}”,访问者='get_last_scan.price.amount',详细名称='last scan price')
last_scan_time=tables.columns.TemplateColumn(“{{record.get_last_scan.datetime}}”,访问器='get_last_scan.datetime',详细名称='last scan time')
difference=tables.columns.TemplateColumn(“{%load static%}{%with diff=record.stats\u get\u difference\u for\u two\u last\u scans.percent%}”
{%if diff>0%}+{%endif%}{{{diff}}%
{%endwith%}”“,详细的名称='Difference')
类元:
模型=发生
字段=(‘id’、‘站点’、‘上次扫描时间’、‘上次扫描价格’、‘差异’、‘平均价格’)
属性={'id':'id\u事件\u表',
'类':'表',}

不知道如何优化模型发生产品的方法。你有什么想法吗?

有了这样的代码,你应该会对你得到的时间感到兴奋

@property
def last_scan_time(self):
    scans = sorted([x for x in self.get_last_scans() if x.datetime],key = lambda x: x.datetime, reverse=True)
    Scan.objects.filter(occurence__product=self,price__amount__isnull=False)
    return str(scans[0].datetime)
这段代码通过调用get_last_scans()检索整个表,然后在python代码中对结果进行排序!数据库具有非常快速的内置排序功能。请用它


在这段代码中还有很多类似的函数。你必须把每一个都修好。在数据库中进行筛选和排序。不在python代码中。

是的,这有一个简单的解决方案(我忘了更改它),但这在表中没有使用,主要问题是优化发生模型的方法,很抱歉将此方法保留在那里。请发布一个新问题,其中包含导致问题的特定视图、模型和模板。换句话说,创建一个Ok,我创建了一个MCVE并进行了测试。加载页面大约需要3秒钟,呈现模板大约需要2秒钟。以下是主题: