您好,登錄后才能下訂單哦!
小編給大家分享一下Python Django開發異常怎么辦,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
1.Django xadmin數據遷移報錯ImportError: cannot 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)
由于xadmin的更新跟不上Django的更新,因此導致了xadmin的很多代碼出錯,需要進行修改,這里將xadmin\plugins\filters.py中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源碼
找到lib\site-packages\django\forms\boundfield.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),如下:
這可能是自定義用戶模型代替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后臺登錄
退出后臺管理登錄,操作如下:
修改用戶模型__str__()
方法
因為自定義用戶如UserProfile繼承自AbstractUser,而AbstractUser模型有username屬性,不允許為空,所以可以設置為返回self.username
,即如下:
def __str__(self): return self.username
此時不登出后臺管理也可以正常訪問。
5.DRF報錯AssertionError: basename
argument 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”參數
,顯然需要在使用router定義路由時指定basename參數,如下:
router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')
即在urls.py中使用router配置路由時加入basename參數即可。
6.UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list
paginator = self.django_paginator_class(queryset, page_size)
在Django Restful framework中實現視圖時對某一類數據進行分頁并在前端請求訪問數據時顯示警告信息如下:
XXX\lib\site-packages\rest_framework\pagination.py:200: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 'goods.models.Goods'> QuerySet. paginator = self.django_paginator_class(queryset, page_size)
提示的是無序對象列表警告,意思是對數據結果進行排序,在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 framework中使用JWT實現自定義驗證{“non_field_errors”:[“無法使用提供的認證信息登錄。”]}
先聲明小編使用的Django版本為3.0,后面有用。
在DRF中使用驗證時經常會使用JSON Web Token進行驗證,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
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', ...}
重新加載之后再次訪問就會訪問到文檔頁面,如下:
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開發異常怎么辦”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。