Werfen Sie einen Blick auf die Ausnahmen und Lösungen für die Python-Django-Entwicklung

coldplay.xixi
Freigeben: 2021-01-07 10:25:52
nach vorne
2492 Leute haben es durchsucht

🔜 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:.

Werfen Sie einen Blick auf die Ausnahmen und Lösungen für die Python-Django-Entwicklung

2. Django xadmin meldet einen Fehler TypeError: render() hat ein unerwartetes Schlüsselwortargument „renderer“ erhalten

Wenn sich Django anmeldet und den xadmin-Hintergrund betritt, wird beim Hinzufügen von Widgets ein Fehler wie folgt gemeldet:

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)
Nach dem Login kopieren
Es gibt zwei Lösungen. Geben Sie ein:
  • Ändern Sie den Django-Quellcode

    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'
Nach dem Login kopieren
Klicken Sie Fügen Sie jetzt Budgets hinzu. Es wird erneut ein Fehler gemeldet.
  • Ändern Sie den xadmin-Code Ändern Sie die Funktion 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,)
Nach dem Login kopieren

解决办法有两种:

  • 修改Django源码
    找到libsite-packagesdjangoformsboundfield.py,找到第96行,注释掉即可,如下:
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.
Nach dem Login kopieren

此时再点击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.

在进行数据库映射时,报错如下:

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']
Nach dem Login kopieren

解决办法是在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
Nach dem Login kopieren

4.Django配置Restful framework报错__str__ returned non-string (type NoneType)

在Django项目中配置Restful framework时,报错__str__ returned non-string (type NoneType),如下:
Werfen Sie einen Blick auf die Ausnahmen und Lösungen für die Python-Django-Entwicklung
这可能是自定义用户模型代替Django自带的用户模型时,允许name(或相似的)字段允许为空,例如name = models.CharField(max_length=30, null=True, blank=True, verbose_name='姓名')所以会返回non-string报错,完整模型如下:

def __str__(self):
    return self.username
Nach dem Login kopieren

解决办法有2种:

  • 退出admin或xadmin后台登录
    退出后台管理登录,操作如下:
    django xadmin logout
  • 修改用户模型__str__()方法
    因为自定义用户如UserProfile继承自AbstractUser,而AbstractUser模型有username属性,不允许为空,所以可以设置为返回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.
Nach dem Login kopieren

此时不登出后台管理也可以正常访问。

5.DRF报错AssertionError: basename argument not specified

在Restful framework中使用过滤器时报错:

router = DefaultRouter()# 配置goods的路由router.register(r'goods', GoodsListViewSet, basename='goods')
Nach dem Login kopieren

报错提示很明显,assert queryset不是None,未指定“basename”参数3.Django xadmin meldet RuntimeError: ist nicht in einer Anwendung in INSTALLED_APPS.

Bei der Datenbankzuordnung wird der Fehler wie folgt gemeldet:

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>
Nach dem Login kopieren
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']
Nach dem Login kopieren

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:

Fehlerseite 4

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',]
Nach dem Login kopieren

Es gibt zwei Lösungen:

  • Beenden Sie den Administrator oder xadmin-Hintergrundanmeldung
Beenden Sie die Hintergrundverwaltungsanmeldung. Der Vorgang ist wie folgt:

 django xadmin logout
  • Ändern Sie die __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
    Nach dem Login kopieren

    Sie können weiterhin normal darauf zugreifen, ohne sich aus dem Hintergrund abzumelden Management.

    5.DRF-Fehler AssertionError: 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),]
    Nach dem Login kopieren
    Nach dem Login kopieren
    🎜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	...
    Nach dem Login kopieren
    Nach dem Login kopieren
    🎜 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)
    Nach dem Login kopieren
    Nach dem Login kopieren
    🎜 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'.
    Nach dem Login kopieren
    Nach dem Login kopieren
    🎜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位验证码'
        })
    Nach dem Login kopieren
    Nach dem Login kopieren
    🎜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'
    Nach dem Login kopieren
    Nach dem Login kopieren
    🎜urls.py“ ist wie folgt konfiguriert: 🎜
    from rest_framework_jwt.views import obtain_jwt_token
    
    urlpatterns = [
           # JWT认证路由
           url(r'^login/', obtain_jwt_token),]
    Nach dem Login kopieren
    Nach dem Login kopieren

    但是在模拟请求访问时却未收到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	...
    Nach dem Login kopieren
    Nach dem Login kopieren

    为了验证是否是版本的问题,我在系统环境中安装了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)
    Nach dem Login kopieren
    Nach dem Login kopieren

    到现在,你们是否发现了什么(^_^)?

    哈哈,你猜的没错,是新版中的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'.
    Nach dem Login kopieren
    Nach dem Login kopieren

    报错提示很明显,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位验证码'
        })
    Nach dem Login kopieren
    Nach dem Login kopieren

    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'
    Nach dem Login kopieren
    Nach dem Login kopieren

    此时需要在settings.py中进行配置:

    # DRF配置REST_FRAMEWORK = {
        ...
        'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
        ...}
    Nach dem Login kopieren

    重新加载之后再次访问就会访问到文档页面,如下:
    DRF 文档

    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 []
    Nach dem Login kopieren

    但是会报错如下:

    if not permission.has_permission(request, self):TypeError: has_permission() missing 1 required positional argument: 'view'
    Nach dem Login kopieren

    这是因为返回的可能是权限类,即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!

    Verwandte Etiketten:
    Quelle:csdn.net
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
    Beliebte Tutorials
    Mehr>
    Neueste Downloads
    Mehr>
    Web-Effekte
    Quellcode der Website
    Website-Materialien
    Frontend-Vorlage