我有一个使用nginx在gunicorn上运行的Django 1.6应用程序。我间歇性地收到错误,它似乎发生在任何写入数据库的页面上。
错误是:
Exception Value: 'module' object has no attribute '\__newobj__'
Traceback:
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
112. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/django/apps/cantifix-direct/products/views.py" in dispatch_product_form
359. return cls.as_view()(request)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/views/generic/base.py" in view
69. return self.dispatch(request, *args, **kwargs)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py" in dispatch
236. response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
87. return handler(request, *args, **kwargs)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py" in post
272. management_form = ManagementForm(self.request.POST, prefix=self.prefix)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/forms/forms.py" in __init__
100. self.fields = copy.deepcopy(self.base_fields)
File "/usr/lib/python2.7/copy.py" in deepcopy
174. y = copier(memo)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/utils/datastructures.py" in __deepcopy__
144. for key, value in self.items()])
File "/usr/lib/python2.7/copy.py" in deepcopy
174. y = copier(memo)
File "/home/django/venvs/cantifix-direct/local/lib/python2.7/site-packages/django/forms/fields.py" in __deepcopy__
188. result = copy.copy(self)
File "/usr/lib/python2.7/copy.py" in copy
88. rv = reductor(2)
Exception Type: AttributeError at /products/configure/
Exception Value: 'module' object has no attribute '__newobj__'
我得到的这个可能是写入数据库的所有页面的三分之一,这很奇怪。
这是我的某个应用中的模型:
https://gist.github.com/anonymous/6648fd6233717c11a462
这是我的views.py
import json
from itertools import groupby
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404, render, redirect
from django.views.generic import DetailView, ListView, FormView, UpdateView
from django.contrib.formtools.wizard.views import SessionWizardView
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.shortcuts import resolve_url
from django.conf import settings
from django.contrib.auth.views import redirect_to_login
from prices import Price
from core.utils import DistanceAwareJSONEncoder, is_expert, apply_vat
from .models import (Product, ProductCustomisation, ProductConfiguration,
PROJECT_TYPE_CHOICES, PROPERTY_TYPE_CHOICES,
OptionsRecommendation, ProductGroup)
from .mixins import ProductOptions
from sales.models import Estimate, Pallet
from . import forms
from customer.models import Address
from delivery.models import DeliveryMethod
class ProductDetailView(DetailView):
model = Product
class ProductGroupListView(ListView):
model = ProductGroup
template_name = 'products/product_groups.html'
def get_queryset(self):
return ProductGroup.objects.filter(hidden=False).order_by('name')
class ProductListView(ListView):
model = Product
template_name = 'products/product_list.html'
def get_queryset(self):
return Product.objects.filter(hidden=False,
group=self.kwargs['pk']).order_by('name')
#------------------------------------------------------------------------------
class GetRangesMixin(object):
def get_dimension_ranges(self):
return {'max_width': self.product.max_frame_width_mm,
'min_height': self.product.min_frame_height_mm,
'max_height': self.product.max_frame_height_mm,
'min_width': self.product.min_frame_width_mm}
class ProductWizardMixin(GetRangesMixin):
def get_recommended_options(self, proj_type, prop_type):
if proj_type is not None:
proj_type = str(proj_type)
if prop_type is not None:
prop_type = str(prop_type)
product = self.get_form_instance(self.steps.current).product
proj_name = dict(PROJECT_TYPE_CHOICES).get(proj_type)
prop_name = dict(PROPERTY_TYPE_CHOICES).get(prop_type)
try:
proj = product.options_recommendation.get(type=proj_type)
except OptionsRecommendation.DoesNotExist:
proj = None
try:
prop = product.options_recommendation.get(type=prop_type)
except OptionsRecommendation.DoesNotExist:
prop = None
recommendations = {}
for name in ProductOptions.get_fields():
proj_val, prop_val = (getattr(proj, name, None),
getattr(prop, name, None))
text = []
if proj_val:
text.append("project type (%s)" %proj_name.lower())
if prop_val:
text.append("property type (%s)" %prop_name.lower())
if not len(text):
continue
text = 'Recommended due to ' + ' and '.join(text)
recommendations[name] = (proj_val or prop_val, text)
return recommendations
def done(self, form_list, **kwargs):
form_data = self.get_all_cleaned_data()
session = self.request.session
self.instance.apply_option_switches()
self.instance.save()
if self.request.user.is_anonymous():
session['project_type'] = form_data.get('project_type')
session['property_type'] = form_data.get('property_type')
else:
user_profile = self.request.user.profile
user_profile.default_project_type = form_data.get('project_type')
user_profile.default_property_type = form_data.get('property_type')
user_profile.save()
approx = form_data.get('approx_dimensions', False)
session['approx_dimensions'] = approx
session['product_customisation_id'] = self.instance.id
session.save()
return redirect('products_product_summary')
def get_template_names(self):
template_name = 'products/%s_%s.html' %(self.template_prefix,
self.steps.current)
return [template_name, 'products/wizard_base.html']
@property
def product(self):
try:
return self.get_cleaned_data_for_step('product').get('product')
except:
return None
def get_form_instance(self, step):
if self.instance is None:
self.instance = ProductCustomisation(product=self.product)
return self.instance
def get_context_data(self, *args, **kwargs):
context = super(ProductWizardMixin, self).get_context_data(*args, **kwargs)
context['product'] = self.product
context['steps'] = [(s.replace('_', ' ').capitalize(), s==self.steps.current)
for s in self.steps.all]
return context
def get_form_initial(self, step):
data = super(ProductWizardMixin, self).get_form_initial(step)
data['user'] = self.request.user
if step == self.project_type_step:
if self.request.user.is_anonymous():
data['project_type'] = self.request.session.get('project_type',None)
data['property_type'] = self.request.session.get('property_type',None)
else:
data['project_type'] = self.request.user.profile.default_project_type
data['property_type'] = self.request.user.profile.default_property_type
if step == 'product':
data['product_id'] = self.request.GET.get('product')
return data
#------------------------------------------------------------------------------
class GuidedView(ProductWizardMixin, SessionWizardView):
template_prefix = 'guided'
approx_dimensions_step = 2
project_type_step = 'project_type'
instance = None
_product = None
_recommendations = None
form_list = [
('project_type', forms.ProjectTypeForm),
('product', forms.ProductForm),
('dimensions', forms.DimensionsForm),
('configuration', forms.ConfigurationForm),
('options', forms.OptionsForm),
]
def get_form_initial(self, step):
data = super(GuidedView, self).get_form_initial(step)
if step == "configuration":
form_data = self.get_cleaned_data_for_step('dimensions')
data['width'] = form_data['width']
elif step == 'product':
form_data = self.get_cleaned_data_for_step(self.project_type_step)
if form_data:
data['project_type'] = form_data['project_type']
data['property_type'] = form_data['property_type']
elif step == "options":
for name, (val, _) in self.recommendations.items():
data[name] = val
return data
@property
def recommendations(self):
if self._recommendations is None:
product = self.get_form_instance('options').product
form_data = self.get_cleaned_data_for_step('project_type')
proj_type = form_data['project_type']
prop_type = form_data['property_type']
self._recommendations = self.get_recommended_options(
proj_type,
prop_type
)
return self._recommendations
def get_context_data(self, form, **kwargs):
context = super(GuidedView, self).get_context_data(form,**kwargs)
if self.steps.current == 'dimensions':
context['ranges'] = self.get_dimension_ranges()
if self.steps.current == 'options':
form_data = [(form[field], self.recommendations.get(field, None))
for field in form.fields]
context['form_data'] = form_data
return context
#------------------------------------------------------------------------------
class ExpertView(ProductWizardMixin, SessionWizardView):
template_prefix = 'expert'
approx_dimensions_step = 1
project_type_step = 'customisation'
_product = None
instance = None
form_list = [
('product', forms.ProductForm),
('customisation', forms.ExpertForm),
]
def get_context_data(self, form, **kwargs):
context = super(ExpertView, self).get_context_data(form, **kwargs)
if self.steps.current == 'customisation':
context['ranges'] = self.get_dimension_ranges()
return context
def post(self, request, *args, **kwargs):
if not request.is_ajax():
return super(ExpertView, self).post(request, *args, **kwargs)
proj_type = request.POST.get('customisation-project_type')
prop_type = request.POST.get('customisation-property_type')
recommendations = self.get_recommended_options(proj_type, prop_type)
return HttpResponse(json.dumps(recommendations),
content_type='application/json')
#------------------------------------------------------------------------------
class ProductSummaryView(FormView):
form_class = forms.SummaryForm
template_name = 'products/summary.html'
@property
def approx_dimensions(self):
return self.request.session.get('approx_dimensions', False)
def get_initial(self):
self.custom = get_custom(self.request)
return {'user': self.request.user,
'address': self.request.GET.get('address'),
'method': self.request.GET.get('method', 1)}
def form_valid(self, form):
return self.render_to_response(self.get_context_data(form=form))
def get_context_data(self, **kwargs):
context = super(ProductSummaryView, self).get_context_data(**kwargs)
form = kwargs['form']
approx_dimensions = self.approx_dimensions
context['user'] = self.request.user
context['custom'] = self.custom
context['total_cost'] = self.custom.total_price
context['approx_dimensions'] = approx_dimensions
form_data = getattr(form, 'cleaned_data', None)
if form_data and not form.errors:
method = form_data.get('delivery_method')
delivery = self.estimate_delivery(
method,
address=form_data.get('delivery_address'),
postcode=form_data.get('delivery_postcode')
)
else:
method = DeliveryMethod.objects.get(id=1).name.lower()
delivery = Price(0, currency='GBP')
context['delivery_method'] = method
context['delivery_price'] = delivery
return context
def estimate_delivery(self, method, address=None, postcode=None):
if address is None:
address = '%s, UK' %postcode
backend = method.get_backend()(
destination=address,
num_items=1, # TODO only one item per product?
weight=self.custom.total_weight,
longest_length=self.custom.longest_length_mm
)
val = backend.get_charge_excl_tax()
return Price(net=val, gross=apply_vat(val), currency='GBP')
#------------------------------------------------------------------------------
class EditProductViewBase(UpdateView, GetRangesMixin):
model = ProductCustomisation
form_class = forms.ExpertForm
template_name = 'products/expert_customisation.html'
def get_initial(self, **kwargs):
return {'user': self.request.user,
'approx_dimensions': self.approx_dimensions}
@property
def reverse_args(self):
return None
def get_success_url(self):
return reverse(self.reverse_url, kwargs=self.reverse_args)
def form_valid(self, form):
form.instance.apply_option_switches()
return super(EditProductViewBase, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(EditProductViewBase, self).get_context_data(**kwargs)
self.product = self.object
context['ranges'] = self.get_dimension_ranges()
context['cancel_url'] = self.get_success_url()
return context
class EditProductView(EditProductViewBase):
reverse_url = 'products_product_summary'
@property
def approx_dimensions(self):
approx = self.request.session.get('approx_dimensions', 'approx')
return 'approx' if approx else 'exact'
def get_object(self, queryset=None):
return get_custom(self.request)
#------------------------------------------------------------------------------
def dispatch_product_form(request):
if request.GET.has_key('mode'):
cls = None
if request.GET['mode'] == 'guided':
cls = GuidedView
elif request.GET['mode'] == 'expert':
cls = ExpertView
if cls is not None:
return cls.as_view()(request)
product = request.GET.get('product')
query = 'mode=guided%s' %('&product=%s'%product if product is not None
else '')
return redirect('%s?%s' %(reverse('products_product_configure'), query))
#------------------------------------------------------------------------------
def get_custom(request):
custom_id = request.session.get('product_customisation_id', None)
return get_object_or_404(ProductCustomisation, id=custom_id)
def remove_custom(request):
request.session.pop('product_customisation_id', None)
@login_required
def create_estimate(request):
return add_for_model(Estimate, request)
@login_required
def create_pallet(request):
return add_for_model(Pallet, request)
@login_required
def add_to_estimate(request, estimate=None):
return add_for_model(Estimate, request, estimate)
@login_required
def add_to_pallet(request, pallet=None):
return add_for_model(Pallet, request, pallet)
def add_for_model(model, request, id=None):
custom = get_custom(request)
kwargs = {}
if model == Estimate:
kwargs['approx_dimensions'] = request.session.get(
'approx_dimensions',
False
)
if id is not None:
obj = get_object_or_404(model, id=id)
if obj.user!=request.user:
raise PermissionDenied
else:
obj = model.objects.create(user=request.user)
obj.add_item(custom, **kwargs)
remove_custom(request)
return redirect(reverse('sales_user_%s_detail' %model.__name__.lower(),
args=(obj.id,)))