#関連する無料学習の推奨事項:
#1. Django xadmin データ移行エラー ImportError: できませんimport name '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)
from django.db.models.sql.query import LOOKUP_SEP, QUERY_TERMS は
from django.db.models.sql.query import LOOKUP_SEP, Query## に変更されます# 47 行目の Query: の
if len(parts) > 1 and Parts[-1] を if len(parts) > 1 and Parts[-1] に変更する必要もあります。 ] QUERY_TERMS:
。
Django が xadmin バックグラウンドにログインするとき、ウィジェットを追加するときに、次のようにエラーが報告されます:
return widget.render(TypeError: render() got an unexpected keyword argument 'renderer'
解決策は 2 つあります:
Django ソース コードを変更しますreturn widget.render( name=self.html_initial_name if only_initial else self.html_name, value=self.value(), attrs=attrs, # renderer=self.form.renderer,)
def render(self, name) に変更します。 , value, attrs=None, renderer=None):
、つまり、レンダラ パラメータを None に増やします。
データベース マッピングを実行すると、エラーが次のように報告されます:
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.
解決策は、次のように
django.contrib.admin を settings.py の INSTALLED_APPS に追加することです: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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']</pre><div class="contentsignin">ログイン後にコピー</div></div>
#Django プロジェクトで Restful フレームワークを構成する場合、次のようなエラー __str__ が非文字列 (型 NoneType) を返しました:
これはカスタム ユーザーである可能性があります。モデルが Django に付属のユーザー モデルを置き換える場合、名前 (または同様の) フィールドは空にすることができます。たとえば、
name = models.CharField(max_length=30, null=True、blank=True、verbose_name='name') したがって、非文字列エラーが返されます。完全なモデルは次のとおりです:
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 つあります:
管理者または xadmin のバックグラウンド ログインを終了します。
バックグラウンド管理ログインを終了します。操作は次のとおりです。self.username
を返すように設定できます。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">def __str__(self):
return self.username</pre><div class="contentsignin">ログイン後にコピー</div></div>
バックグラウンド管理からログアウトしなくても、通常どおりアクセスできます。 5.DRF が AssertionError を報告します:
basename 引数が指定されていませんRestful フレームワークでフィルターを使用すると、エラーが発生します:
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」パラメータが指定されていません
。明らかに、次のように、ルーターを使用してルートを定義するときに、basename パラメータを指定する必要があります。 :router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')
つまり、urls.py に、ルーターを使用してルーティングを構成するときに、basename パラメーターを追加するだけです。
6.UnownedObjectListWarning: ページネーションにより、順序付けされていない object_list と一貫性のない結果が生じる可能性があります。
paginator = self.django_paginator_class(queryset, page_size) Django Restful フレームワークで実装される場合表示すると、特定の種類のデータがページングされ、次のようにフロントエンドがデータへのアクセスを要求すると、警告メッセージが表示されます。
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>
は、順序付けされていないオブジェクト リストの警告を表示します。これは、データの結果を並べ替えることを意味します。 views.py データを取得するときに並べ替えを追加するだけです。デフォルトでは、以下に示すように ID で並べ替えることができます:
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']
7. Django Restful フレームワークで JWT を使用して、カスタム検証 {"non_field_errors":["提供された認証情報を使用してログインできません。"]}
を実装します。最初に宣言します。エディターで使用される Django のバージョンは 3.0 です。これは、後で役立ちます。 DRF で検証を使用する場合、検証には JSON Web トークンがよく使用されます。settings.py 構成は次のとおりです:
# 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 は次のとおりです:
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
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()]
、返回实例化后的对象即可。
以上がPython Django 開発の例外と解決策を見てみましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。