Home>Article>Backend Development> Take a look at Python Django development exceptions and solutions
Related free learning recommendations:python video tutorial
##1. Django xadmin data migration error ImportError: cannot import name 'QUERY_TERMS'
Error when migrating Django xadmin data: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)Because xadmin updates cannot keep up with Django updates, many xadmin code errors occur , need to be modified, here
from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMSin xadmin\plugins\filters.py is modified to
from django.db.models.sql.query import LOOKUP_SEP, Query, you also need to change
if len(parts) > 1 and parts[-1] in Query:in line 47 to
if len(parts) > 1 and parts[-1] in QUERY_TERMS:.
2. Django xadmin reports TypeError: render() got an unexpected keyword argument 'renderer'
When Django logs in to the xadmin background, when adding widgets, An error will be reported, as follows:return widget.render(TypeError: render() got an unexpected keyword argument 'renderer'There are two solutions:
return widget.render( name=self.html_initial_name if only_initial else self.html_name, value=self.value(), attrs=attrs, # renderer=self.form.renderer,)Click Add Budgets at this time and no more errors will be reported.
function in xadmin/views/dashboard.py, and change line 36 to
def render(self, name , value, attrs=None, renderer=None):, that is, increase the renderer parameter to None.
3. Django xadmin reports an error RuntimeError: isn't in an application in INSTALLED_APPS.
When performing database mapping, the error is reported as follows: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.The solution is to add
django.contrib.adminto INSTALLED_APPS in settings.py, as follows:
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 configures Restful framework and reports an error __str__ returned non-string ( type NoneType)
When configuring Restful framework in the Django project, an error __str__ returned non-string (type NoneType) is reported, as follows:
This may be a custom user When the model replaces the user model that comes with Django, the name (or similar) field is allowed to be empty, for example
name = models.CharField(max_length=30, null=True, blank=True, verbose_name='name')So a non-string error will be returned. The complete model is as follows:
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.nameThere are two solutions:
Method
Because custom users such as UserProfile inherit from AbstractUser, and the AbstractUser model has a username attribute, which does not It is allowed to be empty, so it can be set to return, which is as follows:
def __str__(self): return self.usernameYou can still access it normally without logging out of the background management.
5.DRF reports AssertionError:basenameargument not specified
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.The error message is obvious,
assert queryset is not None, and the "basename" parameter is not specified. Obviously, you need to specify the basename parameter when using the router to define the route, as follows:
router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')That is, in urls.py Just add the basename parameter when using router to configure routing.
6.UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list
paginator = self.django_paginator_class(queryset, page_size)Implemented in Django Restful framework When viewing, a certain type of data is paged and the warning message is displayed when the front-end requests access to the data as follows:
XXX\lib\site-packages\rest_framework\pagination.py:200: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list:prompts an unordered object list warning, which means sorting the data results, in views.py Just add sorting when fetching data. By default, you can sort by ID, as shown below:QuerySet. paginator = self.django_paginator_class(queryset, page_size)
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']Run again at this time, and the warning message will no longer be displayed.
7. Use JWT in Django Restful framework to implement custom verification {"non_field_errors":["Unable to log in using the provided authentication information."]}
Declare first The Django version used by the editor is 3.0, which will be useful later.When using verification in DRF, JSON Web Token is often used for verification. The settings.py configuration is as follows:
# 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',]apps/users/views.py is as follows:
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 Noneurls.py The configuration is as follows:
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', ...}
重新加载之后再次访问就会访问到文档页面,如下:
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()]
、返回实例化后的对象即可。
The above is the detailed content of Take a look at Python Django development exceptions and solutions. For more information, please follow other related articles on the PHP Chinese website!