Django 自定义装饰器 - 属性错误
Django Custom Decorator - Attribute Error
编写了我自己的装饰器,为用户获取可用报告,并检查视图是否在这些可用报告中。
这是我的装饰器:
from functools import wraps
from django.http import HttpResponseForbidden
def can_access(a=None):
def _can_access(view_func):
def access(request, *args, **kwargs):
if not request.user.get_reports().filter(codename=a).exists():
return HttpResponseForbidden()
return view_func(request, *args, *kwargs)
return wraps(view_func)(access)
return _can_access
给我这个错误:
'function'对象没有属性'status_code'
views.py
import json
from datetime import datetime, timedelta, date
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
from reporting.enums import ReportFrequency
from base.helpers import get_begin_of_day, get_end_of_day
from billing.helpers import get_fake_usage_by_type, update_license_usage_data
from billing.helpers import get_fake_usage_of_ports, get_fake_usage_by_type, update_license_usage_data, \
get_usage_by_type, get_fake_minutes_use_by_type
from reporting.enums import ReportFrequency
from .forms import UsageByTypeForm, LAST_MONTH
from reporting.decorators import can_access
@login_required
@can_access
def view_update_license_usage_data(request):
update_license_usage_data()
return HttpResponse()
@login_required
@can_access
def billing_home(request):
return render(
request,
'billing_list.html',
{'section': 'billing_index',}
)
@login_required
@can_access
def usage_by_type(request):
user = request.user
client = user.client
form = UsageByTypeForm(
data=request.GET or None,
user=request.user,
initial={
'frequency': ReportFrequency.MONTHLY,
'begin': (datetime.now()-timedelta(days=365)).date(),
'end': datetime.now().date()
}
)
return render(
request,
'usage_by_type_of_source.html',
{'form': form}
)
@login_required
@can_access
def fake_usage_by_type_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
initial = {
'begin': datetime.now()-timedelta(days=365),
'end': datetime.now()
}
)
form.is_valid()
data = get_fake_usage_by_type(
request=request,
data=form.cleaned_data,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def usage_by_type_json(request):
user = request.user
form = UsageByTypeForm(
data=request.GET,
user=user,
)
if not form.is_valid():
return HttpResponseBadRequest('Bad request')
begin = get_begin_of_day(form.cleaned_data['begin'])
end = get_end_of_day(form.cleaned_data['end'])
clients = form.cleaned_data.get('clients', [])
mcus = form.cleaned_data.get('mcus', [])
data = get_usage_by_type(
user=request.user,
begin=user.get_utc_time(begin),
end=user.get_utc_time(end),
freq=form.cleaned_data['frequency'],
client_ids=clients,
mcu_ids=mcus,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def usage_of_ports(request):
user = request.user
client = user.client
form = UsageByTypeForm(
data=request.GET or None,
user=request.user,
initial={
'frequency': ReportFrequency.MONTHLY,
'begin': (datetime.now()-timedelta(days=365)).date(),
'end': datetime.now().date()
}
)
return render(
request,
'usage_of_ports.html',
{'form': form}
)
@login_required
@can_access
def fake_usage_of_ports_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
initial = {
'begin': datetime.now()-timedelta(days=365),
'end': datetime.now()
}
)
form.is_valid()
data = get_fake_usage_of_ports(
request=request,
data=form.cleaned_data,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def usage_of_ports_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
)
if not form.is_valid():
return HttpResponseBadRequest('Bad request')
data = get_usage_by_type(
user=request.user,
begin=form.cleaned_data['begin'],
end=form.cleaned_data['end'],
client_ids=form.cleaned_data['clients'],
mcu_ids=form.cleaned_data['mcus'],
types=None,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def minutes_use_by_type(request):
user = request.user
client = user.client
form = UsageByTypeForm(
data=request.GET or None,
user=request.user,
initial={
'frequency': ReportFrequency.MONTHLY,
'begin': (datetime.now()-timedelta(days=365)).date(),
'end': datetime.now().date()
}
)
return render(
request,
'minute_use_by_type.html',
{'form': form}
)
"""@login_required
@can_access
def minutes_use_by_type_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
)
if not form.is_valid():
return HttpResponseBadRequest('Bad request')
data = get_minutes_use_by_type(
user=request.user,
begin=form.cleaned_data['begin'],
end=form.cleaned_data['end'],
client_ids=form.cleaned_data['clients'],
mcu_ids=form.cleaned_data['mcus'],
types=None,
)
return JsonResponse(data=data, safe=False)"""
@login_required
@can_access
def fake_minutes_use_by_type_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
initial = {
'begin': datetime.now()-timedelta(days=365),
'end': datetime.now()
}
)
form.is_valid()
data = get_fake_minutes_use_by_type(
request=request,
data=form.cleaned_data,
)
return JsonResponse(data=data, safe=False)
装饰器在另一个应用程序中(报告)
这是怎么回事,如何解决??
PD。我对同一个应用程序的看法(报告)它没有问题。
Traceback:
File "/Users/latin/Documents/booking_center/env/lib/python3.6/site-packages/django/core/handlers/base.py" in get_response
223. response = middleware_method(request, response)
File "/Users/latin/Documents/booking_center/env/lib/python3.6/site-packages/django/middleware/locale.py" in process_response
39. if (response.status_code == 404 and not language_from_path
Exception Type: AttributeError at /reports/billing/time_usage_per_licence/
Exception Value: 'function' object has no attribute 'status_code'
你装饰的方式不对。您应该通过调用 can_access(..)
来修饰函数 ,例如:
@login_required
@can_access<b>()</b> # with brackets
def view_update_license_usage_data(request):
# ...
pass
@login_required
@can_access<b>(a='some_a_value')</b> # with brackets
def billing_home(request):
# ...
pass
(也适用于其他视图函数)
这应该发生,因为 can_access
本身实际上 不是 装饰函数。 can_access
是一个 工厂, 生产 装饰函数。确实:
def can_access(a=None): # function producing the decorator
def <b>_can_access</b>(view_func): # the actual decorator
def access(request, *args, **kwargs): # the new (decorated) function
if not request.user.get_reports().filter(codename=a).exists():
return HttpResponseForbidden()
return view_func(request, *args, *kwargs)
return wraps(view_func)(access) # return (decorated) function
return _can_access # return *decorator
如果我们这样做 不 在装饰语句中使用括号,Python 将用 can_access
本身装饰 view
。因此 a=view_update_license_usage_data
,然后“decorated”函数是 _can_access(view_func)
.
因此,request
对象将通过 view_func
参数传递。这个"view"不会return一个HttpResponse
,而是一个函数(access(..)
函数),而这个函数没有status_code
,因此Django实际上会失败生成 HTTP 响应,因为它不知道要填写什么作为状态、消息等。
而且由于我们都喜欢装饰,所以通常最好也用 @wraps
装饰器来装饰被装饰的函数:
def can_access(a=None): # function producing the decorator
def _can_access(view_func): # the actual decorator
<b>@wraps(view_func)</b>
def access(request, *args, **kwargs): # the new (decorated) function
if not request.user.get_reports().filter(codename=a).exists():
return HttpResponseForbidden()
return view_func(request, *args, *kwargs)
return <b>access</b> # return (decorated) function
return _can_access # return *decorator
编写了我自己的装饰器,为用户获取可用报告,并检查视图是否在这些可用报告中。
这是我的装饰器:
from functools import wraps
from django.http import HttpResponseForbidden
def can_access(a=None):
def _can_access(view_func):
def access(request, *args, **kwargs):
if not request.user.get_reports().filter(codename=a).exists():
return HttpResponseForbidden()
return view_func(request, *args, *kwargs)
return wraps(view_func)(access)
return _can_access
给我这个错误:
'function'对象没有属性'status_code'
views.py
import json
from datetime import datetime, timedelta, date
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
from reporting.enums import ReportFrequency
from base.helpers import get_begin_of_day, get_end_of_day
from billing.helpers import get_fake_usage_by_type, update_license_usage_data
from billing.helpers import get_fake_usage_of_ports, get_fake_usage_by_type, update_license_usage_data, \
get_usage_by_type, get_fake_minutes_use_by_type
from reporting.enums import ReportFrequency
from .forms import UsageByTypeForm, LAST_MONTH
from reporting.decorators import can_access
@login_required
@can_access
def view_update_license_usage_data(request):
update_license_usage_data()
return HttpResponse()
@login_required
@can_access
def billing_home(request):
return render(
request,
'billing_list.html',
{'section': 'billing_index',}
)
@login_required
@can_access
def usage_by_type(request):
user = request.user
client = user.client
form = UsageByTypeForm(
data=request.GET or None,
user=request.user,
initial={
'frequency': ReportFrequency.MONTHLY,
'begin': (datetime.now()-timedelta(days=365)).date(),
'end': datetime.now().date()
}
)
return render(
request,
'usage_by_type_of_source.html',
{'form': form}
)
@login_required
@can_access
def fake_usage_by_type_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
initial = {
'begin': datetime.now()-timedelta(days=365),
'end': datetime.now()
}
)
form.is_valid()
data = get_fake_usage_by_type(
request=request,
data=form.cleaned_data,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def usage_by_type_json(request):
user = request.user
form = UsageByTypeForm(
data=request.GET,
user=user,
)
if not form.is_valid():
return HttpResponseBadRequest('Bad request')
begin = get_begin_of_day(form.cleaned_data['begin'])
end = get_end_of_day(form.cleaned_data['end'])
clients = form.cleaned_data.get('clients', [])
mcus = form.cleaned_data.get('mcus', [])
data = get_usage_by_type(
user=request.user,
begin=user.get_utc_time(begin),
end=user.get_utc_time(end),
freq=form.cleaned_data['frequency'],
client_ids=clients,
mcu_ids=mcus,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def usage_of_ports(request):
user = request.user
client = user.client
form = UsageByTypeForm(
data=request.GET or None,
user=request.user,
initial={
'frequency': ReportFrequency.MONTHLY,
'begin': (datetime.now()-timedelta(days=365)).date(),
'end': datetime.now().date()
}
)
return render(
request,
'usage_of_ports.html',
{'form': form}
)
@login_required
@can_access
def fake_usage_of_ports_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
initial = {
'begin': datetime.now()-timedelta(days=365),
'end': datetime.now()
}
)
form.is_valid()
data = get_fake_usage_of_ports(
request=request,
data=form.cleaned_data,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def usage_of_ports_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
)
if not form.is_valid():
return HttpResponseBadRequest('Bad request')
data = get_usage_by_type(
user=request.user,
begin=form.cleaned_data['begin'],
end=form.cleaned_data['end'],
client_ids=form.cleaned_data['clients'],
mcu_ids=form.cleaned_data['mcus'],
types=None,
)
return JsonResponse(data=data, safe=False)
@login_required
@can_access
def minutes_use_by_type(request):
user = request.user
client = user.client
form = UsageByTypeForm(
data=request.GET or None,
user=request.user,
initial={
'frequency': ReportFrequency.MONTHLY,
'begin': (datetime.now()-timedelta(days=365)).date(),
'end': datetime.now().date()
}
)
return render(
request,
'minute_use_by_type.html',
{'form': form}
)
"""@login_required
@can_access
def minutes_use_by_type_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
)
if not form.is_valid():
return HttpResponseBadRequest('Bad request')
data = get_minutes_use_by_type(
user=request.user,
begin=form.cleaned_data['begin'],
end=form.cleaned_data['end'],
client_ids=form.cleaned_data['clients'],
mcu_ids=form.cleaned_data['mcus'],
types=None,
)
return JsonResponse(data=data, safe=False)"""
@login_required
@can_access
def fake_minutes_use_by_type_json(request):
form = UsageByTypeForm(
data=request.GET,
user=request.user,
initial = {
'begin': datetime.now()-timedelta(days=365),
'end': datetime.now()
}
)
form.is_valid()
data = get_fake_minutes_use_by_type(
request=request,
data=form.cleaned_data,
)
return JsonResponse(data=data, safe=False)
装饰器在另一个应用程序中(报告)
这是怎么回事,如何解决??
PD。我对同一个应用程序的看法(报告)它没有问题。
Traceback:
File "/Users/latin/Documents/booking_center/env/lib/python3.6/site-packages/django/core/handlers/base.py" in get_response
223. response = middleware_method(request, response)
File "/Users/latin/Documents/booking_center/env/lib/python3.6/site-packages/django/middleware/locale.py" in process_response
39. if (response.status_code == 404 and not language_from_path
Exception Type: AttributeError at /reports/billing/time_usage_per_licence/
Exception Value: 'function' object has no attribute 'status_code'
你装饰的方式不对。您应该通过调用 can_access(..)
来修饰函数 ,例如:
@login_required
@can_access<b>()</b> # with brackets
def view_update_license_usage_data(request):
# ...
pass
@login_required
@can_access<b>(a='some_a_value')</b> # with brackets
def billing_home(request):
# ...
pass
(也适用于其他视图函数)
这应该发生,因为 can_access
本身实际上 不是 装饰函数。 can_access
是一个 工厂, 生产 装饰函数。确实:
def can_access(a=None): # function producing the decorator
def <b>_can_access</b>(view_func): # the actual decorator
def access(request, *args, **kwargs): # the new (decorated) function
if not request.user.get_reports().filter(codename=a).exists():
return HttpResponseForbidden()
return view_func(request, *args, *kwargs)
return wraps(view_func)(access) # return (decorated) function
return _can_access # return *decorator
如果我们这样做 不 在装饰语句中使用括号,Python 将用 can_access
本身装饰 view
。因此 a=view_update_license_usage_data
,然后“decorated”函数是 _can_access(view_func)
.
因此,request
对象将通过 view_func
参数传递。这个"view"不会return一个HttpResponse
,而是一个函数(access(..)
函数),而这个函数没有status_code
,因此Django实际上会失败生成 HTTP 响应,因为它不知道要填写什么作为状态、消息等。
而且由于我们都喜欢装饰,所以通常最好也用 @wraps
装饰器来装饰被装饰的函数:
def can_access(a=None): # function producing the decorator
def _can_access(view_func): # the actual decorator
<b>@wraps(view_func)</b>
def access(request, *args, **kwargs): # the new (decorated) function
if not request.user.get_reports().filter(codename=a).exists():
return HttpResponseForbidden()
return view_func(request, *args, *kwargs)
return <b>access</b> # return (decorated) function
return _can_access # return *decorator