Python Django 개발 예외 및 솔루션 살펴보기

coldplay.xixi
풀어 주다: 2021-01-07 10:25:52
앞으로
2429명이 탐색했습니다.

Python Django 개발 예외 및 솔루션 살펴보기

관련 무료 학습 권장사항:python 비디오 튜토리얼

1.Django xadmin 데이터 마이그레이션 오류 ImportError: 'QUERY_TERMS' 이름을 가져올 수 없습니다.

Django xadmin 데이터 마이그레이션 수행 시 오류:

from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMS ImportError: cannot import name 'QUERY_TERMS' from 'django.db.models.sql.query' (C:\Users\LENOVO\.virtualenvs\Django_Vue_Fresh_Ecommerce-NKba4OvD\lib\site-packages\django\db\models\sql\query.py)
로그인 후 복사

다음으로 인해 발생합니다. xadmin의 업데이트는 Django의 업데이트를 따라갈 수 없으므로 xadmin에서 많은 코드 오류가 발생하므로 수정이 필요합니다. 여기서from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMSxadminpluginsfilters.py에서from django.db.models.sql.query import LOOKUP_SEP, Query를 수정하고if len(parts) > -1] in Query:if len(parts) > 1 및 parts[-1] in QUERY_TERMS:로 수정하세요.from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMS修改为from django.db.models.sql.query import LOOKUP_SEP, Query,还需要将47行的if len(parts) > 1 and parts[-1] in Query:修改为if len(parts) > 1 and parts[-1] in QUERY_TERMS:

2.Django xadmin报错TypeError: render() got an unexpected keyword argument ‘renderer’

在Django登录进入xadmin后台时,在添加小部件时,会报错,如下:

return widget.render(TypeError: render() got an unexpected keyword argument 'renderer'
로그인 후 복사

解决办法有两种:

  • 修改Django源码
    找到libsite-packagesdjangoformsboundfield.py,找到第96行,注释掉即可,如下:
return widget.render( name=self.html_initial_name if only_initial else self.html_name, value=self.value(), attrs=attrs, # renderer=self.form.renderer,)
로그인 후 복사

此时再点击Add Budgets就不会再报错了。

  • 修改xadmin代码
    在xadmin/views/dashboard.py中修改render()函数,第36行改为def render(self, name, value, attrs=None, renderer=None):,即增加renderer参数为None。

两种方法皆可,但是个人建议采用第二种方法,因为xadmin是外部引入到extra_apps作为外部的app,本身就可能经过了一定修改,在此基础上再修改也影响不大,而django是虚拟环境所带的依赖库,相当于是系统文件,因此不要轻易修改。

3.Django xadmin报错RuntimeError: isn’t in an application in INSTALLED_APPS.

在进行数据库映射时,报错如下:

raise RuntimeError(RuntimeError: Model class django.contrib.admin.models.LogEntry doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
로그인 후 복사

解决办法是在settings.py中的INSTALLED_APPS中增加django.contrib.admin,如下:

INSTALLED_APPS = [ 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'apps.users.apps.UsersConfig', 'goods', 'trade', 'user_operation', 'DjangoUeditor', 'xadmin', 'crispy_forms', 'django.contrib.admin']
로그인 후 복사

4.Django配置Restful framework报错__str__ returned non-string (type NoneType)

在Django项目中配置Restful framework时,报错__str__ returned non-string (type NoneType),如下:
Python Django 개발 예외 및 솔루션 살펴보기
这可能是自定义用户模型代替Django自带的用户模型时,允许name(或相似的)字段允许为空,例如name = models.CharField(max_length=30, null=True, blank=True, verbose_name='姓名')所以会返回non-string报错,完整模型如下:

class UserProfile(AbstractUser): '''用户''' name = models.CharField(max_length=30, null=True, blank=True, verbose_name='姓名') birthday = models.DateField(null=True, blank=True, verbose_name='出生日期') gender = models.CharField(max_length=6, choices=(('male', u'男'), ('female', u'女')), default='female', verbose_name='性别') mobile = models.CharField(max_length=11, verbose_name='电话') email = models.CharField(max_length=50, null=True, blank=True, verbose_name='邮箱') is_delete = models.BooleanField(default=False, verbose_name='是否删除') class Meta: verbose_name = '用户' verbose_name_plural = '用户' def __str__(self): return self.name
로그인 후 복사

解决办法有2种:

  • 退出admin或xadmin后台登录
    退出后台管理登录,操作如下:
    django xadmin logout
  • 修改用户模型__str__()方法
    因为自定义用户如UserProfile继承自AbstractUser,而AbstractUser模型有username属性,不允许为空,所以可以设置为返回self.username,即如下:
def __str__(self): return self.username
로그인 후 복사

此时不登出后台管理也可以正常访问。

5.DRF报错AssertionError:basenameargument not specified

在Restful framework中使用过滤器时报错:

assert queryset is not None, '`basename` argument not specified, and could ' \ AssertionError: `basename` argument not specified, and could not automatically determine the name from the viewset, as it does not have a `.queryset` attribute.
로그인 후 복사

报错提示很明显,assert queryset不是None,未指定“basename”参数

2. Django xadmin에서 TypeError: render()에 예기치 않은 키워드 인수 'renderer'가 있음을 보고합니다.

Django가 로그인하고 xadmin 배경에 들어가면 위젯을 추가할 때 다음과 같은 오류가 보고됩니다.두 가지 해결 방법이 있습니다.

  • Django 소스 코드 수정

    libsite-packagesdjangoformsboundfield.py를 찾아 96행을 찾아 다음과 같이 주석 처리합니다.

router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')
로그인 후 복사

클릭 지금 예산을 추가하면 오류가 다시 보고됩니다.
  • xadmin 코드 수정

    xadmin/views/dashboard.py의render()함수를 수정하고 36행을def render(self, name, value)로 변경하세요. , attrs=None, renderer=None):, 즉 렌더러 매개변수를 None으로 늘립니다.

두 가지 방법 모두 가능하지만 xadmin이 외부 앱으로 extra_apps에 외부적으로 도입되어 어느 정도 수정을 거쳤을 수도 있고 이를 토대로 수정하기 때문에 개인적으로는 두 번째 방법을 사용하는 것을 추천합니다. 영향이 거의 없고 django는 가상환경에서 가져온 종속 라이브러리로 시스템 파일과 동일하므로 쉽게 수정하지 마세요.

3.Django xadmin이 RuntimeError: is not in an application in INSTALLED_APPS.

데이터베이스 매핑을 수행할 때 오류는 다음과 같이 보고됩니다.

XXX\lib\site-packages\rest_framework\pagination.py:200: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list:  QuerySet. paginator = self.django_paginator_class(queryset, page_size)
로그인 후 복사

해결책은 django를 설정에서 INSTALLED_APPS에 추가하는 것입니다. .py .contrib.admin, 다음과 같습니다:
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): '''商品列表页,并实现分页、搜索、过滤、排序''' queryset = Goods.objects.filter(is_delete=False).order_by('id') # 添加根据id排序即可 serializer_class = GoodsSerializer pagination_class = GoodsPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filter_class = GoodsFilter search_fields = ['name', 'goods_brief', 'goods_desc'] ordering_fields = ['sold_num', 'shop_price']
로그인 후 복사

4.Django는 Restful 프레임워크를 구성하고 __str__이 문자열이 아닌 문자열을 반환했습니다(NoneType 유형)

Django 프로젝트에서 Restful 프레임워크를 구성할 때, 오류 __str__은 다음과 같이 문자열이 아닌(NoneType 유형)을 반환했습니다. 이는 사용자 정의 사용자 모델이 Django와 함께 제공되는 사용자 모델을 대체하여 이름(또는 유사한) 필드를 비워 둘 수 있는 경우일 수 있습니다. 예를 들어 name = models.CharField(max_length=30, null=True, 공백=True, verbose_name='name')따라서 문자열이 아닌 오류가 반환됩니다. 전체 모델은 다음과 같습니다.
# DRF配置REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ]}# 自定义用户认证配置AUTHENTICATION_BACKENDS = [ 'users.views.CustomBackend',]
로그인 후 복사
두 가지 해결 방법이 있습니다.
  • admin 또는 xadmin 백그라운드 로그인 종료 백그라운드 관리 로그인 종료, 작업은 다음과 같습니다:
  • 사용자 모델__str__()메서드 수정 UserProfile과 같은 사용자 정의 사용자는 AbstractUser에서 상속되고 AbstractUser 모델에는 사용자 이름 속성이 있기 때문입니다. 비워 둘 수 없으므로 다음과 같이self.username을 반환하도록 설정할 수 있습니다.
from django.db.models import Qfrom django.contrib.auth.backends import ModelBackendfrom django.contrib.auth import get_user_model User = get_user_model()# Create your views here.class CustomBackend(ModelBackend): '''自定义用户验证''' def authenticate(self, username=None, password=None, **kwargs): try: print(123) user = User.objects.get(Q(username=username)|Q(mobile=username)) if user.check_password(password) and user.is_delete != True: print(456) return user except Exception as e: return None
로그인 후 복사
로그아웃하지 않고도 정상적으로 접속할 수 있습니다. 배경 관리의. 5.DRF 오류 AssertionError: basename인수가 지정되지 않았습니다Restful 프레임워크에서 필터를 사용할 때 오류가 발생합니다.
from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ # JWT认证路由 url(r'^login/', obtain_jwt_token),]
로그인 후 복사
로그인 후 복사
오류 메시지는 분명합니다. assert queryset은 다음과 같습니다. not None, not None "basename" 매개변수를 지정하세요. 라우터를 사용하여 경로를 정의할 때 다음과 같이 basename 매개변수를 지정해야 합니다.
class ModelBackend(BaseBackend): """ Authenticates against settings.AUTH_USER_MODEL. """ def authenticate(self, request, username=None, password=None, **kwargs): if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) if username is None or password is None: return try: user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a nonexistent user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user ...
로그인 후 복사
로그인 후 복사
즉, basename 매개변수를 추가하면 됩니다. urls.py에서 경로를 구성하는 라우터입니다. 6.UnorderedObjectListWarning: 순서가 지정되지 않은 object_list를 사용하면 페이지 매기기가 일관되지 않은 결과를 초래할 수 있습니다.paginator = self.django_paginator_class(queryset, page_size) Django Restful 프레임워크에서 뷰를 구현할 때 특정 유형의 데이터에 페이지를 매기고 해당 페이지에 대한 액세스를 요청하세요. 프런트 엔드 데이터가 표시될 때 다음과 같이 경고 메시지가 표시됩니다.
class ModelBackend(object): """ Authenticates against settings.AUTH_USER_MODEL. """ def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) try: user = UserModel._default_manager.get_by_natural_key(username) if user.check_password(password): return user except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user (#20760). UserModel().set_password(password)
로그인 후 복사
로그인 후 복사
는 데이터 결과를 정렬하라는 순서가 지정되지 않은 개체 목록 경고를 표시합니다. views.py에서 데이터를 가져올 때 정렬을 추가하면 됩니다. id는 아래와 같습니다.
raise type(exc)(msg)AttributeError: Got AttributeError when attempting to get a value for field `code` on serializer `UserRegSerializer`.The serializer field might be named incorrectly and not match any attribute or key on the `UserProfile` instance.Original exception text was: 'UserProfile' object has no attribute 'code'.
로그인 후 복사
로그인 후 복사
지금 실행하면 경고 메시지가 더 이상 표시되지 않습니다. 7. Django Restful 프레임워크에서 JWT를 사용하여 사용자 정의 확인을 구현합니다. {"non_field_errors":["Unable to log in using the 제공된 인증 정보."]} 먼저 편집기에서 사용하는 Django 버전을 선언하겠습니다. 3.0이며 나중에 유용할 것입니다. DRF에서 검증을 사용할 때 JSON 웹 토큰이 검증에 자주 사용됩니다. settings.py 구성은 다음과 같습니다.
code = serializers.CharField(max_length=4, min_length=4, write_only=True, label='验证码', help_text='验证码', error_messages={ 'required': '请输入验证码', 'blank': '请输入验证码', 'max_length': '请输入4位验证码', 'min_length': '请输入4位验证码' })
로그인 후 복사
로그인 후 복사
apps/users/views.py는 다음과 같습니다.
link = view.schema.get_link(path, method, base_url=self.url)AttributeError: 'AutoSchema' object has no attribute 'get_link'
로그인 후 복사
로그인 후 복사
urls.py는 다음과 같이 구성됩니다.
from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ # JWT认证路由 url(r'^login/', obtain_jwt_token),]
로그인 후 복사
로그인 후 복사

但是在模拟请求访问时却未收到token,只提示错误信息{"non_field_errors":["无法使用提供的认证信息登录。"]},这让我很苦恼,明明所有配置都没问题啊,百思不得姐,到底哪里出了问题了呢?一直不停的排错、Debug,却还是一样的错误,这让我很郁闷。最后不得不去求助于JWT官方文档,看到环境要求仿佛有点儿感觉了:

Requirements
Python (2.7, 3.3, 3.4, 3.5)
Django (1.8, 1.9, 1.10)
Django REST Framework (3.0, 3.1, 3.2, 3.3, 3.4, 3.5)

这里要求的最高Django版本为1.9,而我自己的Django版本为3.0,凭直觉立马想到会不会是版本不兼容的问题,导致了某些地方不一致。jwt部分就不说了,本身版本没怎么更新,可能问题出在了Django和DRF上面,而最有可能出问题的就是自定义验证类,CustomBackend继承自ModelBackend,于是我到django.contrib.auth.backends源码中查看,其定义如下:

class ModelBackend(BaseBackend): """ Authenticates against settings.AUTH_USER_MODEL. """ def authenticate(self, request, username=None, password=None, **kwargs): if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) if username is None or password is None: return try: user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a nonexistent user (#20760). UserModel().set_password(password) else: if user.check_password(password) and self.user_can_authenticate(user): return user ...
로그인 후 복사
로그인 후 복사

为了验证是否是版本的问题,我在系统环境中安装了JWT指定的Django版本1.9用于进行对比,再查看django.contrib.auth.backends.py:

class ModelBackend(object): """ Authenticates against settings.AUTH_USER_MODEL. """ def authenticate(self, username=None, password=None, **kwargs): UserModel = get_user_model() if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) try: user = UserModel._default_manager.get_by_natural_key(username) if user.check_password(password): return user except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user (#20760). UserModel().set_password(password)
로그인 후 복사
로그인 후 복사

到现在,你们是否发现了什么(^_^)?

哈哈,你猜的没错,是新版中的authenticate()方法发生了改变,增加了request参数,而自定义验证类时就是继承ModelBackend类并重写authenticate()方法,而我使用的参数采用的是老版本中的参数,与本应继承的新版本中的方法参数不一致,所以就不是重写是重载了,所以在请求时验证调用的方法并不是自定义的authenticate(),而是ModelBackend类中的authenticate()方法明白怎么回事了就赶紧改了试试,再次测试{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNTk1ODk2MTc3LCJlbWFpbCI6IjEyM0AxMjMuY29tIn0.pblxNy4s4XBrqmnsfI9-dmx3Q8rErqq1WbN4rfBSZfI"},一片光明,真是版本不兼容害苦了我,以后得注意了。

8.Django使用DRF实现注册功能报错Got AttributeError when attempting to get a value

在使用DRF实现注册功能时,前端的用户名(手机号)、验证码、邮箱传到后端处理时,由于验证码不属于用户的一个字段,但是为了验证又必须设置该字段,如果不注意,就容易报错,一般如下:

raise type(exc)(msg)AttributeError: Got AttributeError when attempting to get a value for field `code` on serializer `UserRegSerializer`.The serializer field might be named incorrectly and not match any attribute or key on the `UserProfile` instance.Original exception text was: 'UserProfile' object has no attribute 'code'.
로그인 후 복사
로그인 후 복사

报错提示很明显,UserProfile没有code属性。具体来说,这是因为Meta中指定了fields = ['username', 'code', 'mobile', 'password'],包含code字段,而在验证时为了判断验证码的正误而临时加入code字段,但是在validate(attrs)又将其删去,导致在序列化时找不到code字段,因此出错,这是需要将字段的write_only设置True,以确保在更新或创建实例时可以使用该字段,但是在序列化表示形式时不包括该字段,即设置为如下即可:

code = serializers.CharField(max_length=4, min_length=4, write_only=True, label='验证码', help_text='验证码', error_messages={ 'required': '请输入验证码', 'blank': '请输入验证码', 'max_length': '请输入4位验证码', 'min_length': '请输入4位验证码' })
로그인 후 복사
로그인 후 복사

9.DRF访问文档路由报错AttributeError: ‘AutoSchema’ object has no attribute ‘get_link’

DRF提供了文档功能,无需再专门写文档即可同步使用文档,但是在访问http://127.0.0.1:8000/docs/的时候可能报错:

link = view.schema.get_link(path, method, base_url=self.url)AttributeError: 'AutoSchema' object has no attribute 'get_link'
로그인 후 복사
로그인 후 복사

此时需要在settings.py中进行配置:

# DRF配置REST_FRAMEWORK = { ... 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema', ...}
로그인 후 복사

重新加载之后再次访问就会访问到文档页面,如下:
DRF 文档

10.DRF动态设置权限

在DRF中经常会用到权限,一般情况下是在视图ViewSet类下设置属性permission_classes = [IsAuthenticated, IsOwnerOrReadOnly],但是这对于请求的所有方法(如create、retrieve、list)均有效,不能对不同的方法进行不同的限制,因此可以进行动态设置权限,即重写get_permissions()方法,针对不同地方法返回不同的权限,如下:

def get_permissions(self): '''动态设置权限''' if self.action == 'retrieve': return [IsAuthenticated] elif self.action == 'create': return [] return []
로그인 후 복사

但是会报错如下:

if not permission.has_permission(request, self):TypeError: has_permission() missing 1 required positional argument: 'view'
로그인 후 복사

这是因为返回的可能是权限类,即return [IsAuthenticated],这里只是返回了一个权限类,并没有实例化,即没有初始化,导致APIView在初始化时没有传入正确的权限,因此报错,修改为return [IsAuthenticated()]、返回实例化后的对象即可。

위 내용은 Python Django 개발 예외 및 솔루션 살펴보기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:csdn.net
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!