1
매우 간단하고 직선적 인 관리자보기 중 하나가 nginx
시간 초과까지로드되는 데 이상한 동작이 발생했습니다.Django admin : field_sets 블록에서보기가 중단됩니다.
~ Django debug toolbar
과 new relic
나는 죄책감 코드가 장고 템플릿의 field_sets
블록이라는 것을 알았습니다. 디버그가 더 어려워졌습니다.
생산시보기가로드되면 비어 있습니다.
이렇게 처음 만난 것은 이번이 처음이므로 커뮤니티에 도움을 청하기로 결정했습니다.
모델 : 모델이 많은 항목이 모델에ForeignKey
또는
ManyToManyField
있다
from datetime import timedelta
from decimal import Decimal
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from django.utils.crypto import get_random_string
from django.utils.translation import ugettext as _
from core.common.models import (SoftDeletableModel, TimeStampedModel,
UniqueFieldMixin, FlagableMixin)
from core.models import Pair
from payments.utils import money_format
from ticker.models import Price
from django.core.exceptions import ValidationError
class Order(TimeStampedModel, SoftDeletableModel,
UniqueFieldMixin, FlagableMixin):
USD = "USD"
RUB = "RUB"
EUR = "EUR"
BTC = "BTC"
EXCHANGE = 2
BUY = 1
SELL = 0
TYPES = (
(SELL, 'SELL'),
(BUY, 'BUY'),
(EXCHANGE, 'EXCHANGE'),
)
_order_type_help = '{} - {}<br/>{} - {}<br/>{} - {}<br/>'.format(
'BUY', 'Customer is giving fiat, and getting crypto money.',
'SELL', 'Customer is giving crypto and getting fiat money',
'EXCHANGE', 'Customer is exchanging different kinds of crypto '
'currencies'
)
PAID_UNCONFIRMED = -1
CANCELED = 0
INITIAL = 1
PAID = 2
RELEASED = 3
COMPLETED = 4
STATUS_TYPES = (
(PAID_UNCONFIRMED, 'UNCONFIRMED PAYMENT'),
(CANCELED, 'CANCELED'),
(INITIAL, 'INITIAL'),
(PAID, 'PAID'),
(RELEASED, 'RELEASED'),
(COMPLETED, 'COMPLETED'),
)
IN_PAID = [PAID, RELEASED, COMPLETED]
IN_RELEASED = [RELEASED, COMPLETED]
_could_be_paid_msg = 'Could be paid by crypto transaction or fiat ' \
'payment, depending on order_type.'
_order_status_help =\
'{} - {}<br/>{} - {}<br/>{} - {}<br/>' \
'{} - {}<br/>{} - {}<br/>{} - {}<br/>'\
.format(
'INITIAL', 'Initial status of the order.',
'PAID', 'Order is Paid by customer. ' + _could_be_paid_msg,
'PAID_UNCONFIRMED', 'Order is possibly paid (unconfirmed crypto '
'transaction or fiat payment is to small to '
'cover the order.)',
'RELEASED', 'Order is paid by service provider. ' + _could_be_paid_msg,
'COMPLETED', 'All statuses of the order is completed',
'CANCELED', 'Order is canceled.'
)
# Todo: inherit from BTC base?, move lengths to settings?
order_type = models.IntegerField(
choices=TYPES, default=BUY,
# help_text=_order_type_help
)
status = models.IntegerField(choices=STATUS_TYPES, default=INITIAL,
# help_text=_order_status_help
)
amount_base = models.DecimalField(max_digits=18, decimal_places=8)
amount_quote = models.DecimalField(max_digits=18, decimal_places=8)
payment_window = models.IntegerField(default=settings.PAYMENT_WINDOW)
user = models.ForeignKey(User, related_name='orders')
unique_reference = models.CharField(
max_length=settings.UNIQUE_REFERENCE_MAX_LENGTH)
admin_comment = models.CharField(max_length=200)
payment_preference = models.ForeignKey('payments.PaymentPreference',
default=None,
null=True)
withdraw_address = models.ForeignKey('core.Address',
null=True,
related_name='order_set',
default=None)
is_default_rule = models.BooleanField(default=False)
from_default_rule = models.BooleanField(default=False)
pair = models.ForeignKey(Pair)
price = models.ForeignKey(Price, null=True, blank=True)
user_marked_as_paid = models.BooleanField(default=False)
system_marked_as_paid = models.BooleanField(default=False)
class Meta:
ordering = ['-created_on']
# unique_together = ['deleted', 'unique_reference']
def validate_unique(self, exclude=None):
# TODO: exclude expired?
if not self.deleted and \
Order.objects.exclude(pk=self.pk).filter(
unique_reference=self.unique_reference,
deleted=False).exists():
raise ValidationError(
'Un-deleted order with same reference exists')
super(Order, self).validate_unique(exclude=exclude)
def _types_range_constraint(self, field, types):
""" This is used for validating IntegerField's with choices.
Assures that value is in range of choices.
"""
if field > max([i[0] for i in types]):
raise ValidationError(_('Invalid order type choice'))
elif field < min([i[0] for i in types]):
raise ValidationError(_('Invalid order type choice'))
def _validate_fields(self):
self._types_range_constraint(self.order_type, self.TYPES)
self._types_range_constraint(self.status, self.STATUS_TYPES)
def clean(self, *args, **kwargs):
self._validate_fields()
super(Order, self).clean(*args, **kwargs)
def save(self, *args, **kwargs):
self._validate_fields()
if not self.unique_reference:
self.unique_reference = \
self.gen_unique_value(
lambda x: get_random_string(x),
lambda x: Order.objects.filter(unique_reference=x).count(),
settings.UNIQUE_REFERENCE_LENGTH
)
if self.status == self.INITIAL:
self.convert_coin_to_cash()
super(Order, self).save(*args, **kwargs)
def _not_supported_exchange_msg(self):
msg = _('Sorry, we cannot convert {} to {}'.format(
self.currency_from.code, self.currency_to.code
))
return msg
def convert_coin_to_cash(self):
self.amount_base = Decimal(self.amount_base)
price = Price.objects.filter(pair=self.pair).last()
self.price = price
# For annotations
amount_quote = None
if self.order_type == Order.BUY:
amount_quote = self.amount_base * price.ticker.ask
elif self.order_type == Order.SELL:
amount_quote = self.amount_base * price.ticker.bid
self.amount_quote = money_format(amount_quote)
@property
def is_buy(self):
return self.order_type == Order.BUY
@property
def payment_deadline(self):
"""returns datetime of payment_deadline (creation + payment_window)"""
# TODO: Use this for pay until message on 'order success' screen
return self.created_on + timedelta(minutes=self.payment_window)
@property
def expired(self):
"""Is expired if payment_deadline is exceeded and it's not paid yet"""
# TODO: validate this business rule
# TODO: Refactor, it is unreasonable to have different standards of
# time in the DB
return (timezone.now() > self.payment_deadline) and (
self.status not in Order.IN_PAID)
@property
def payment_status_frozen(self):
"""return a boolean indicating if order can be updated
Order is frozen if it is expired or has been paid
"""
# TODO: validate this business rule
return self.expired or self.status in Order.IN_RELEASED
@property
def withdrawal_address_frozen(self):
"""return bool whether the withdraw address can
be changed"""
return self.status in Order.IN_RELEASED
def __str__(self):
return "{} {} pair:{} base:{} quote:{} status:{}".format(
self.user.username or self.user.profile.phone,
self.get_order_type_display(),
self.pair.name,
self.amount_base,
self.amount_quote,
self.get_status_display()
)
지적합니까? 모델 관리 클래스에서 [raw_id_fields'] (https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields)를 사용해야 할 수도 있습니다. – Alasdair
하지만 알 수 있듯이 SQL에서 보낸 시간은 매우 적거나 뭔가 빠졌는가? 신속한 답변을 보내 주셔서 감사합니다! –
그것은 단지 제안 일뿐입니다. 나는'field_sets' 블록이하는 일에 익숙하지 않아 일반적인 문제이기 때문에'raw_id_fields'를 언급했습니다. 데이터베이스에서 1000 개 항목을 가져 오는 것은 빠르지 만 드롭 다운에 1000 개의 옵션을 렌더링하는 것은 아닙니다. – Alasdair