Heim > Artikel > Backend-Entwicklung > Werfen Sie einen Blick auf die Ausnahmen und Lösungen für die Python-Django-Entwicklung
🔜 Aufgrund Die Updates von xadmin können nicht mit den Updates von Django mithalten, was zu vielen Codefehlern in xadmin führt und hier geändert werden muss: von django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMS
in xadminpluginsfilters.py Ändern Sie von django.db.models.sql.query import LOOKUP_SEP, Query
, und ändern Sie auch Zeile 47 von if len(parts) > -1] in der Abfrage:
Ändern in wenn len(parts) > 1 und parts[-1] in QUERY_TERMS:
.
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)Es gibt zwei Lösungen. Geben Sie ein:
Suchen Sie libsite-packagesdjangoformsboundfield.py, suchen Sie Zeile 96 und kommentieren Sie sie wie folgt aus:
return widget.render(TypeError: render() got an unexpected keyword argument 'renderer'Klicken Sie Fügen Sie jetzt Budgets hinzu. Es wird erneut ein Fehler gemeldet.
render()
in xadmin/views/dashboard.py und ändern Sie Zeile 36 in def render(self, name, value , attrs=None, renderer=None):
, das heißt, erhöhen Sie den Renderer-Parameter auf None. Beide Methoden sind möglich, aber ich persönlich empfehle die Verwendung der zweiten Methode, da xadmin extern als externe App in extra_apps eingeführt wird und möglicherweise bestimmte Änderungen erfahren hat, und dann auf dieser Basis modifizieren Es hat nur geringe Auswirkungen und Django ist eine abhängige Bibliothek, die von der virtuellen Umgebung bereitgestellt wird und einer Systemdatei entspricht. Ändern Sie sie daher nicht einfach.
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( name=self.html_initial_name if only_initial else self.html_name, value=self.value(), attrs=attrs, # renderer=self.form.renderer,)
解决办法有两种:
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.
此时再点击Add Budgets就不会再报错了。
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.
在进行数据库映射时,报错如下:
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']
解决办法是在settings.py中的INSTALLED_APPS中增加django.contrib.admin
,如下:
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
4.Django配置Restful framework报错__str__ returned non-string (type NoneType)
在Django项目中配置Restful framework时,报错__str__ returned non-string (type NoneType),如下:
这可能是自定义用户模型代替Django自带的用户模型时,允许name(或相似的)字段允许为空,例如name = models.CharField(max_length=30, null=True, blank=True, verbose_name='姓名')
所以会返回non-string报错,完整模型如下:
def __str__(self): return self.username
解决办法有2种:
__str__()
方法self.username
,即如下: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.
此时不登出后台管理也可以正常访问。
5.DRF报错AssertionError: basename
argument not specified
在Restful framework中使用过滤器时报错:
router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')
报错提示很明显,assert queryset不是None,未指定“basename”参数
3.Django xadmin meldet RuntimeError: ist nicht in einer Anwendung in INSTALLED_APPS.
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>Die Lösung besteht darin,
django zu INSTALLED_APPS in den Einstellungen hinzuzufügen .py .contrib.admin
, wie folgt: 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 konfiguriert das Restful-Framework und meldet den Fehler __str__, der nicht als Zeichenfolge zurückgegeben wurde (Typ NoneType)
Beim Konfigurieren des Restful-Frameworks im Django-Projekt wurde der Fehler __str__ zurückgegeben Nicht-String (Typ NoneType), wie folgt:
Dies kann der Fall sein, wenn ein benutzerdefiniertes Benutzermodell das mit Django gelieferte Benutzermodell ersetzt, sodass das Namensfeld (oder ein ähnliches Feld) leer sein kann, zum Beispiel name = models.CharField(max_length=30, null=True , blank=True, verbose_name='name')
Es wird also ein Nicht-String-Fehler zurückgegeben. Das vollständige Modell sieht wie folgt aus:
# 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',]
Es gibt zwei Lösungen:
Beenden Sie die Hintergrundverwaltungsanmeldung. Der Vorgang ist wie folgt:
__str__()
-Methode des Benutzermodells Da benutzerdefinierte Benutzer wie UserProfile von AbstractUser erben und das AbstractUser-Modell über ein Benutzernamenattribut verfügt, das dies nicht ist darf leer sein, daher kann es so eingestellt werden, dass es self.username
zurückgibt, was wie folgt lautet:
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
basename
-Argument nicht angegeben🎜Bei Verwendung des Filters im Restful-Framework tritt ein Fehler auf: 🎜from rest_framework_jwt.views import obtain_jwt_token urlpatterns = [ # JWT认证路由 url(r'^login/', obtain_jwt_token),]🎜Die Fehlermeldung ist offensichtlich,
assert queryset is nicht None, nicht None Geben Sie den Parameter „basename“ an
Offensichtlich müssen Sie den Parameter „basename“ angeben, wenn Sie den Router verwenden, um die Route wie folgt zu definieren: 🎜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 ...🎜 Das heißt, fügen Sie einfach den Parameter „basename“ hinzu, wenn Sie den verwenden router, um die Route in urls.py zu konfigurieren. 🎜🎜🎜6.UnorderedObjectListWarnung: Die Paginierung kann bei einer ungeordneten Objektliste zu inkonsistenten Ergebnissen führen. 🎜🎜🎜paginator = self.django_paginator_class(queryset, page_size) Frontend Die Warnmeldung wird wie folgt angezeigt: 🎜
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)🎜 löst eine Warnung vor einer ungeordneten Objektliste aus, was bedeutet, dass beim Abrufen von Daten in „views.py“ einfach eine Sortierung hinzugefügt werden soll id, wie unten gezeigt: 🎜
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'.🎜Führen Sie es jetzt aus und die Warnmeldung wird nicht mehr angezeigt. 🎜🎜🎜7. Verwenden Sie JWT im Django Restful-Framework, um eine benutzerdefinierte Überprüfung zu implementieren Der Editor ist 3.0, was später nützlich sein wird. 🎜 Bei Verwendung der Verifizierung in DRF wird häufig das JSON-Web-Token zur Verifizierung verwendet. Die Konfiguration von „settings.py“ lautet wie folgt: „🎜
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“ lautet wie folgt: „🎜
link = view.schema.get_link(path, method, base_url=self.url)AttributeError: 'AutoSchema' object has no attribute 'get_link'🎜urls.py“ ist wie folgt konfiguriert: 🎜
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()]
、返回实例化后的对象即可。
Das obige ist der detaillierte Inhalt vonWerfen Sie einen Blick auf die Ausnahmen und Lösungen für die Python-Django-Entwicklung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!