Maison > Article > développement back-end > Jetez un œil aux exceptions et solutions de développement Python Django
Recommandations d'apprentissage gratuites associées : Tutoriel vidéo Python
1. Erreur de migration de données Django xadmin ImportError : impossible d'importer le nom 'QUERY_TERMS'
Erreur lors de la migration des données 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)
Parce que les mises à jour xadmin ne peuvent pas suivre les mises à jour de Django, de nombreuses erreurs de code xadmin se produisent et doivent être modifiées. Ici, from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMS
dans xadminpluginsfilters.py doit être modifié en from django.db.models.sql.query import LOOKUP_SEP, Query
, et le if len(parts) > 1 and parts[-1] in Query:
à la ligne 47 doit être modifié en if len(parts) > 1 and parts[-1] in QUERY_TERMS:
.
2. Django xadmin signale TypeError : render() a obtenu un argument de mot-clé inattendu 'renderer'
Lorsque Django se connecte à l'arrière-plan de xadmin, lors de l'ajout de widgets, An l'erreur sera signalée, comme suit :
return widget.render(TypeError: render() got an unexpected keyword argument 'renderer'
Il existe deux 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,)
Cliquez sur Ajouter des budgets à ce moment et l'erreur ne sera plus signalée.
render()
dans xadmin/views/dashboard.py, remplacez la ligne 36 par def render(self, name, value, attrs=None, renderer=None):
, c'est-à-dire ajoutez le paramètre de rendu à Aucun. Les deux méthodes sont possibles, mais je recommande personnellement d'utiliser la deuxième méthode, car xadmin est introduit en externe dans extra_apps en tant qu'application externe, et il peut avoir subi certaines modifications, puis le modifier sur cette base Cela a peu d'impact, et Django est une bibliothèque dépendante apportée par l'environnement virtuel, qui équivaut à un fichier système, donc ne la modifiez pas facilement.
3. Django xadmin a signalé une erreur RuntimeError : n'est pas dans une application dans INSTALLED_APPS.
Lors de l'exécution du mappage de base de données, l'erreur a été signalée comme suit :
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.
La solution est d'ajouter django.contrib.admin
à INSTALLED_APPS dans settings.py, comme suit :
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 configure le framework Restful et signale une erreur __str__ renvoyée sans chaîne (type NoneType)
Lors de la configuration du framework Restful dans le projet Django, une erreur __str__ renvoyée sans chaîne (type NoneType) est signalée, comme suit :
Cela peut être un modèle utilisateur personnalisé au lieu du modèle utilisateur fourni avec Django. Lorsque le champ nom (ou similaire) peut être vide, tel que name = models.CharField(max_length=30, null=True, blank=True, verbose_name='姓名')
, une erreur non-chaîne sera donc renvoyée. Le modèle complet est le suivant :
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
Il existe deux solutions :
__str__()
Méthodeself.username
, qui se présente comme suit : def __str__(self): return self.username
A ce moment, vous pouvez toujours y accéder normalement sans vous déconnecter de la gestion en arrière-plan.
Erreur 5.DRF AssertionError : basename
argument non spécifié
Lors de l'utilisation de filtres dans le framework Restful, un message d'erreur est signalé :
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.
Le message d'erreur est très évidemment, assert queryset不是None,未指定“basename”参数
, il est évidemment nécessaire de spécifier le paramètre basename lors de l'utilisation du routeur pour définir la route, comme suit :
router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')
Autrement dit, ajoutez simplement le paramètre basename lors de l'utilisation du routeur pour configurer la route dans urls.py.
6.UnorderedObjectListWarning : La pagination peut donner des résultats incohérents avec une liste d'objets non ordonnée
paginator = self.django_paginator_class(queryset, page_size)
Implémenté dans le framework Django Restful lorsque Lors de la visualisation, un certain type de données est paginé et le message d'avertissement s'affiche lorsque le frontal demande l'accès aux données comme suit :
XXX\lib\site-packages\rest_framework\pagination.py:200: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class> QuerySet. paginator = self.django_paginator_class(queryset, page_size)</class>
provoque un avertissement de liste d'objets non ordonnés, ce qui signifie trier les résultats des données, dans vues.py Ajoutez simplement un tri lors de la récupération des données. Par défaut, vous pouvez trier par ID, comme indiqué ci-dessous :
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']
Exécutez-le à ce moment-là, et le message d'avertissement ne sera plus affiché.
7. Utilisez JWT dans le framework Django Restful pour implémenter la vérification personnalisée {"non_field_errors":["Impossible de se connecter à l'aide des informations d'authentification fournies."]}
Déclarez d'abord La version de Django utilisée par l'éditeur est la 3.0, ce qui sera utile plus tard.
Lors de l'utilisation de la vérification dans DRF, le jeton Web JSON est souvent utilisé pour la vérification. La configuration settings.py est la suivante :
# 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 est la suivante :
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<.>urls.py La configuration est la suivante :
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()]
、返回实例化后的对象即可。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!