ÀÖÓãµç¾º

½ÌÓýÐÐÒµA¹ÉIPOµÚÒ»¹É£¨¹ÉƱ´úÂë 003032£©

È«¹ú×Éѯ/ͶËßÈÈÏߣº400-618-4000

djangoµ¥Ôª²âÊÔ£ºÈçºÎÖ´Ðе¥Ôª²âÊÔ£¿

¸üÐÂʱ¼ä:2020Äê08ÔÂ07ÈÕ17ʱ43·Ö À´Ô´:ÀÖÓã²¥¿Í ä¯ÀÀ´ÎÊý:

ÔÚ Django ÏîÄ¿ÖУ¬ÎÒÃÇ¿ª·¢ÍêһЩ¹¦ÄÜÄ£¿éÖ®ºó£¬Í¨³£ÐèҪȥдµ¥Ôª²âÊÔÀ´¼ì²â´úÂëµÄ bug¡£Django ¿ò¼ÜÄÚ²¿Ìṩ±È½Ï·½±ãµÄµ¥Ôª²âÊÔ¹¤¾ß£¬½ÓÏÂÀ´ÎÒÃÇÖ÷ÒªÀ´Ñ§Ï°ÈçºÎд Django µÄµ¥Ôª²âÊÔ£¬ÒÔ¼°²âÊÔ Django ÊÓͼº¯ÊýµÄ·½Ê½ºÍÔ­ÀídzÎö¡£

»·¾³×¼±¸

н¨ÏîÄ¿ºÍÓ¦ÓÃ


$ # Ð½¨ django_example ÏîÄ¿
$ django-admin startproject django_example
$ # ½øÈë django_example
$ cd django_example
$ # Ð½¨ users Ó¦ÓÃ
$ ./manage.py startapp users

¸üРdjango_example ÏîÄ¿µÄÅäÖÃÎļþ£¬Ìí¼Ó users Ó¦ÓÃÌí¼Óµ½ INSTALLED_APPS ÖУ¬¹Ø±Õ csrf Öмä¼þ¡£


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ÏîĿĿ¼½á¹¹ÈçÏÂ:


django_example
©À©¤©¤ django_example
©¦   ©À©¤©¤ __init__.py
©¦   ©À©¤©¤ settings.py
©¦   ©À©¤©¤ urls.py
©¦   ©¸©¤©¤ wsgi.py
©À©¤©¤ manage.py
©¸©¤©¤ users
    ©À©¤©¤ __init__.py
    ©À©¤©¤ admin.py
    ©À©¤©¤ apps.py
    ©À©¤©¤ migrations
    ©¦   ©¸©¤©¤ __init__.py
    ©À©¤©¤ models.py
    ©À©¤©¤ tests.py
    ©¸©¤©¤ views.py

½« users/views.py ¸ÄΪÈçÏÂÄÚÈÝ


import json


from django.contrib.auth import login, authenticate, logout
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse


class UserView(View):
    def get(selfrequest):

        if not request.user.is_authenticated:
            return JsonResponse({
                'code'401,
                'message''Óû§Î´µÇ¼'
            })
        return JsonResponse({
            'code'200,
            'message''OK',
            'data': {
                'username': request.user.username,
            }
        })


class SessionView(View):
    def post(selfrequest):
        """Óû§µÇ¼"""
        # ¿Í»§¶ËµÄÇëÇóÌåÊÇ json ¸ñʽ
        content_type = request.headers.get('Content-Type''')
        if 'application/json' in content_type:
            data = json.loads(request.body)
        else:
            return JsonResponse({
                'code'400,
                'message''·Ç json ¸ñʽ'
            })

        data = json.loads(request.body)
        username = data.get('username''')
        password = data.get('password''')

        user = authenticate(username=username,
                            password=password)

        # ¼ì²éÓû§ÊÇ·ñ´æÔÚ
        if not user:
            return JsonResponse({
                'code'400,
                'message''Óû§Ãû»òÃÜÂë´íÎó'
            })

        # Ö´ÐеǼ
        login(request, user)

        return JsonResponse({
            'code'201,
            'message''OK'
        })

    def delete(selfrequest):
        """Í˳öµÇ¼"""
        logout(request)
        return JsonResponse({
            'code'204,
            'message''OK'
        })

ÔÚ django_example/urls.py °ó¶¨½Ó¿Ú


from django.contrib import admin
from django.urls import path

from users.views import UserView, SessionView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users', UserView.as_view()),
    path('session', SessionView.as_view())
]

³õʼ»¯Êý¾Ý¿â


$ ./manage.py makemigrations
$ ./manage.py migrate


Django µ¥Ôª²âÊÔ½éÉÜ

ÉÏÃæµÄ»·¾³×¼±¸ÖÐÎÒÃÇдÁË 2 ¸öÀàÊÓͼ£¬SessionView ÌṩÁËÓû§µÇ¼¡¢Í˳ö½Ó¿Ú£¬UserView ÌṩÁË»ñÈ¡Óû§ÐÅÏ¢½Ó¿Ú¡£½ÓÏÂÀ´ÎÒÃÇÖ÷ÒªÀ´¿´ÈçºÎÕë¶ÔÕâЩ½Ó¿Úдµ¥Ôª²âÊÔ¡£

ÔÚÄĶùÀïдµ¥Ôª²âÊÔ

DjangoÖÐÿһ¸öÓ¦ÓÃÏÂÃæ¶¼»áÓÐÒ»¸ö tests.py Îļþ£¬ÎÒÃǽ«µ±Ç°Ó¦ÓòâÊÔ´úÂëдÔÚÕâ¸öÎļþÖС£Èç¹û²âÊԵĴúÂëÁ¿±È½Ï¶à£¬ÎÒÃÇÐèÒª½«²âÊԵĴúÂë·ÖÄ£¿é£¬ÄÇô¿ÉÒÔÔÚµ±Ç°Ó¦ÓÃÏ´´½¨ tests °ü¡£

µ¥Ôª²âÊÔ´úÂëÈçºÎд

django ÌṩÁË django.test.TestCase µ¥Ôª²âÊÔ»ù´¡À࣬Ëü¼Ì³Ð×Ô python ±ê×¼¿âÖÐ unittest.TestCase ¡£

ÎÒÃÇͨ³£¶¨ÒåÀà¼Ì³Ð×Ô django.test.TestCase £¬ÔÚÀàÖÐÎÒÃǶ¨Òå test_ ¿ªÍ·µÄ·½·¨£¬ÔÚ·½·¨ÖÐд¾ßÌåµÄ²âÊÔÂß¼­£¬Ò»¸öÀàÖпÉÒÔ°üº¬¶à¸ö ²âÊÔ·½·¨¡£

2¸öÌØÊâµÄ·½·¨:

·def setUp(self) Õâ¸ö·½·¨»áÔÚÿһ¸ö²âÊÔ·½·¨Ö´ÐÐ֮ǰ±»µ÷Óã¬Í¨³£ÓÃÀ´×öһЩ׼±¸¹¤×÷

·def tearDown(self) Õâ¸ö·½·¨»áÔÚÿһ¸ö²âÊÔÓ÷¨Ö´ÐÐÖ®ºó±»±»µ÷Óã¬Í¨³£ÓÃÀ´×öһЩÇåÀí¹¤×÷

2 ¸öÌØÊâµÄÀà·½·¨


@classmethod
def setUpClass(cls
# Õâ¸ö·½·¨ÓÃÓÚ×öÀ༶±ðµÄ×¼±¸¹¤×÷£¬Ëû»áÔÚ²âÊÔÖ´ÐÐ֮ǰ±»µ÷Óã¬ÇÒÒ»¸öÀàÖУ¬Ö»±»µ÷ÓÃÒ»´Î
  
@classmthod
def tearDownClass(cls):
# Õâ¸ö·½·¨ÓÃÓÚ×öÀ༶±ðµÄ×¼±¸¹¤×÷£¬Ëû»áÔÚ²âÊÔÖ´ÐнáÊøºó±»µ÷Óã¬ÇÒÒ»¸öÀàÖУ¬Ö»±»µ÷ÓÃÒ»´Î

Django »¹ÊÇÌṩÁË django.test.client.Client ¿Í»§¶ËÀ࣬ÓÃÓÚÄ£Äâ¿Í»§¶Ë·¢Æð [get|post|delete...] ÇëÇ󣬲¢ÇÒÄܹ»×Ô¶¯±£´æ cookie¡£

Client »¹°üº¬ÁË login ·½·¨·½±ã½øÐÐÓû§µÇ¼¡£

ͨ¹ý client ·¢ÆðÇëÇóµÄʱºò url ÊÇ·¾¶£¬²»ÐèÒª schema://domain Õâ¸öǰ׺

ÈçºÎÖ´Ðе¥Ôª²âÊÔ

./manage.py test

Èç¹ûÏëÖµ²âÊÔ¾ßÌåµÄ app£¬»òÕß app ϵÄij¸ö²âÊÔÎļþ£¬²âÊÔÀ࣬²âÊÔ·½·¨£¬Ò²ÊÇ¿ÉÒԵģ¬ÃüÁî²ÎÊýÈçÏÂ([] ±íʾ¿ÉÑ¡):

./manage.py test [app_name][.test_file_name][.class_name][.test_method_name]

²âÊÔ´úÂë

users/tests.py


from django.test import TestCase
from django.test.client import Client

from django.contrib.auth.models import User


class UserTestCase(TestCase):

    def setUp(self):
        # ´´½¨²âÊÔÓû§
        self.username = 'zhangsan'
        self.password = 'zhangsan12345'
        self.user = User.objects.create_user(
            username=self.username, password=self.password)
        # ÊµÀý»¯ client ¶ÔÏó
        self.client = Client()
        # µÇ¼
        self.client.login(username=self.username, password=self.password)

    def tearDown(self):
        # É¾³ý²âÊÔÓû§
        self.user.delete()

    def test_user(self):
        """²âÊÔ»ñÈ¡Óû§ÐÅÏ¢½Ó¿Ú"""
        path = '/users'
        resp = self.client.get(path)
        result = resp.json()

        self.assertEqual(result['code'], 200, result['message'])


class SessionTestCase(TestCase):
    @classmethod
    def setUpClass(cls):
        # ´´½¨²âÊÔÓû§
        cls.username = 'lisi'
        cls.password = 'lisi'
        cls.user = User.objects.create_user(
            username=cls.username, password=cls.password)
        # ÊµÀý»¯ client ¶ÔÏó
        cls.client = Client()

    @classmethod
    def tearDownClass(cls):
        # É¾³ý²âÊÔÓû§
        cls.user.delete()

    def test_login(self):
        """²âÊԵǼ½Ó¿Ú"""
        path = '/session'
        auth_data = {
            'username'self.username,
            'password'self.password
        }
        # ÕâÀïÎÒÃÇÉèÖÃÇëÇóÌå¸ñʽΪ json
        resp = self.client.post(path, data=auth_data,
                                content_type='application/json')
        # ½«ÏàÓ¦Ìåת»¯Îªpython ×Öµä
        result = resp.json()
        # ¼ì²éµÇ¼½á¹û
        self.assertEqual(result['code'], 201, result['message'])

    def test_logout(self):
        """²âÊÔÍ˳ö½Ó¿Ú"""
        path = '/session'
        resp = self.client.delete(path)

        result = resp.json()
        self.assertEqual(result['code'], 204, result['message'])

²âÊÔ½á¹û


$ ./manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.309s

OK
Destroying test database for alias 'default'...


²âÊÔÊÓͼº¯ÊýµÄ·½Ê½

ÉÏÃæµÄ´úÂëÊÇÎÒÃDzâÊÔÊÓͼº¯Êý×î¼ò±ãµÄ·½Ê½£¬ÎÒÃÇÊÇͨ¹ý client ¶ÔÏóÄ£ÄâÇëÇ󣬸ÃÇëÇó×îÖÕ»á·Óɵ½ÊÓͼº¯Êý£¬²¢µ÷ÓÃÊÓͼº¯Êý¡£

ÏÂÃæÎÒÃÇ¿´¿´²»Í¨¹ý client£¬ÔÚ²âÊÔ·½·¨ÖÐÖ±½Óµ÷ÓÃÊÓͼº¯Êý¡£

ÀûÓà RequestFactory Ö±½Óµ÷ÓÃÊÓͼº¯Êý

´ó¼ÒÖªµÀÿ¸öÊÓͼº¯Êý¶¼ÓÐÒ»¸ö¹Ì¶¨²ÎÊý request£¬Õâ¸ö²ÎÊýÊǿͻ§¶ËÇëÇó¶ÔÏó¡£Èç¹ûÎÒÃÇÐèÒªÖ±½Ó²âÊÔÊÓͼº¯Êý£¬ÄÇô±ØÐëÄ£ÄâÕâ¸öÇëÇó¶ÔÏó£¬È»ºó´«µÝ¸øÊÓͼº¯Êý¡£

django ÌṩÁËÄ£ÄâÇëÇó¶ÔÏóµÄÀà `django.test.client.RequestFactory` ÎÒÃÇͨ¹ý RequestFactory ¶ÔÏóµÄ` [get|post|delete|...]` ·½·¨À´Ä£ÄâÇëÇó¶ÔÏ󣬽«¸Ã¶ÔÏ󴫵ݸøÊÓͼº¯Êý£¬À´ÊµÏÖÊÓͼº¯ÊýµÄÖ±½Óµ÷ÓòâÊÔ¡£

ÑÝʾ´úÂë:


class SessionRequestFactoryTestCase(TestCase):
    @classmethod
    def setUpClass(cls):
        # ´´½¨²âÊÔÓû§
        cls.username = 'wangwu'
        cls.password = 'wangwu1234'
        cls.user = User.objects.create_user(
            username=cls.username, password=cls.password)

    @classmethod
    def tearDownClass(cls):
        # É¾³ý²âÊÔÓû§
        cls.user.delete()

    def test_login(self):
        """²âÊԵǼÊÓͼº¯Êý"""
        # ÊµÀý»¯ RequestFactory
        request_factory = RequestFactory()
        path = '/session'
        auth_data = {
            'username'self.username,
            'password'self.password
        }
        # ¹¹½¨ÇëÇó¶ÔÏó
        request = request_factory.post(path, data=auth_data,
                                content_type='application/json')
        
        # µÇ¼µÄÊÓͼº¯Êý
        login_funciton = SessionView().post

        # µ÷ÓÃÊÓͼº¯Êý
        resp = login_funciton(request)

        # ´òÓ¡ÊÓͼº¯Êý·µ»ØµÄÏìÓ¦¶ÔÏóµÄ content£¬Ò²¾ÍÊÇÏìÓ¦Ìå
        print(resp.content)
       

    def test_logout(self):
        """²âÊÔÍ˳öÊÓͼº¯Êý"""
        # ÊµÀý»¯ RequestFactory
        request_factory = RequestFactory()
        path = '/session'
        request = request_factory.delete(path)

        # Í˳öµÄÊÓͼº¯Êý
        logout_funciton = SessionView().delete

         # µ÷ÓÃÊÓͼº¯Êý
        resp = logout_funciton(request)
        
        # ´òÓ¡ÊÓͼº¯Êý·µ»ØµÄÏìÓ¦¶ÔÏóµÄ content£¬Ò²¾ÍÊÇÏìÓ¦Ìå
        print(resp.content)

Èç¹û´ËʱÎÒÃÇÖ´ÐвâÊԵϰ£¬»áÅ׳öÒì³£ÐÅÏ¢ AttributeError: 'WSGIRequest' object has no attribute 'session' ¡£

Ô­Òò·ÖÎö

session ÊÓͼº¯Êý get,post »áµ÷ÓÃlogin ºÍ logout º¯Êý£¬ÎÒÃÇÀ´¿´ÏÂÕâÁ½¸öº¯ÊýµÄÔ´Âë


def login(requestuserbackend=None):
    """
    Persist a user id and a backend in the request. This way a user doesn't
    have to reauthenticate on every request. Note that data set during
    the anonymous session is retained when the user logs in.
    """
    session_auth_hash = ''
    if user is None:
        user = request.user
    if hasattr(user, 'get_session_auth_hash'):
        session_auth_hash = user.get_session_auth_hash()

    if SESSION_KEY in request.session:
        if _get_user_session_key(request) != user.pk or (
                session_auth_hash and
                not constant_time_compare(request.session.get(HASH_SESSION_KEY, ''), session_auth_hash)):
            # To avoid reusing another user's session, create a new, empty
            # session if the existing session corresponds to a different
            # authenticated user.
            request.session.flush()
    else:
        request.session.cycle_key()

    try:
        backend = backend or user.backend
    except AttributeError:
        backends = _get_backends(return_tuples=True)
        if len(backends) == 1:
            _, backend = backends[0]
        else:
            raise ValueError(
                'You have multiple authentication backends configured and '
                'therefore must provide the `backend` argument or set the '
                '`backend` attribute on the user.'
            )
    else:
        if not isinstance(backend, str):
            raise TypeError('backend must be a dotted import path string (got %r).' % backend)

    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    request.session[BACKEND_SESSION_KEY] = backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
        request.user = user
    rotate_token(request)
    user_logged_in.send(sender=user.__class__request=request, user=user)


def logout(request):
# .....
    # remember language choice saved to session
    language = request.session.get(LANGUAGE_SESSION_KEY)

    request.session.flush()

# ......

´Ó´úÂëÖÐÎÒÃÇ¿ÉÒÔ¿´³öÕâÁ½¸ö·½·¨ÖÐÐèÒª¶Ô request ¶ÔÏóµÄ session ÊôÐÔ½øÐÐÏà¹Ø²Ù×÷¡£

¶ø django ÖÐ session ÊÇͨ¹ý django.contrib.sessions.middleware.SessionMiddleware Õâ¸öÖмä¼þÀ´Íê³É£¬Ô´ÂëÈçÏÂ:


class SessionMiddleware(MiddlewareMixin):
    def __init__(selfget_response=None):
        self.get_response = get_response
        engine = import_module(settings.SESSION_ENGINE)
        self.SessionStore = engine.SessionStore

    def process_request(selfrequest):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        # ÉèÖÃÁË session ÊôÐÔ
        request.session = self.SessionStore(session_key)
# ......

ÎÒÃÇ¿ÉÒÔ¿´³ö session ÊôÐÔÊÇÔÚ SessionMiddleware.process_request ÖÐÉèÖõÄ¡£

ÎÒÃÇͨ¹ý RequestFactory Ö»ÊÇ´´½¨ÁËÇëÇó¶ÔÏó£¬Ã»Óб»Öмä¼þ´¦Àí¹ý£¬ËùÒÔÒ²¾ÍÇëÇó¶ÔÏóÖÐÒ²¾ÍûÓÐÁË session ÊôÐÔ¡£

½â¾ö°ì·¨

¼ÈȻijЩÇëÇó¶ÔÏóÐèÒª¾­¹ýÖмä¼þ´¦Àí£¬ÄÇôÎÒÃÇÊÇ·ñ¿ÉÒÔÊÖ¶¯µ÷ÓÃÖмä¼þ´¦ÀíÒ»ÏÂÄØ?´ð°¸Êǿ϶¨µÄ¡£ÎÒÃÇÔÚµ÷ÓÃÊÓͼº¯ÊýǰÏÈÈÃÖмä¼þ´¦ÀíÒ»ÏÂÇëÇó¶ÔÏó¡£


from django.contrib.sessions.middleware import SessionMiddleware

# .....
    def test_login(self):
        """²âÊԵǼÊÓͼº¯Êý"""
        # ÊµÀý»¯ RequestFactory
        request_factory = RequestFactory()
        path = '/session'
        auth_data = {
            'username'self.username,
            'password'self.password
        }
        # ¹¹½¨ÇëÇó¶ÔÏó
        request = request_factory.post(path, data=auth_data,
                                content_type='application/json')

        # µ÷ÓÃÖмä¼þ´¦Àí
        session_middleware = SessionMiddleware()
        session_middleware.process_request(request)
        
        # µÇ¼µÄÊÓͼº¯Êý
        login_funciton = SessionView().post

        # µ÷ÓÃÊÓͼº¯Êý
        resp = login_funciton(request)

        # ´òÓ¡ÊÓͼº¯Êý·µ»ØµÄÏìÓ¦¶ÔÏóµÄ content£¬Ò²¾ÍÊÇÏìÓ¦Ìå
        print(resp.content)
       

    def test_logout(self):
        """²âÊÔÍ˳öÊÓͼº¯Êý"""
        # ÊµÀý»¯ RequestFactory
        request_factory = RequestFactory()
        path = '/session'
        request = request_factory.delete(path)

        # µ÷ÓÃÖмä¼þ´¦Àí
        session_middleware = SessionMiddleware()
        session_middleware.process_request(request)
        
        # Í˳öµÄÊÓͼº¯Êý
        logout_funciton = SessionView().delete

         # µ÷ÓÃÊÓͼº¯Êý
        resp = logout_funciton(request)
        
        # ´òÓ¡ÊÓͼº¯Êý·µ»ØµÄÏìÓ¦¶ÔÏóµÄ content£¬Ò²¾ÍÊÇÏìÓ¦Ìå
        print(resp.content)

×ܽá

ÎÒÃÇͨ¹ý RequestFactory Ä£ÄâµÄÇëÇó¶ÔÏó£¬È»ºó´«µÝ¸øÊÓͼº¯Êý£¬À´Íê³ÉÊÓͼº¯ÊýµÄÖ±½Óµ÷ÓòâÊÔ£¬Èç¹ûÐèÒª¾­¹ýÖмä¼þµÄ´¦Àí£¬ÎÒÃÇÐèÒªÊÖ¶¯µ÷ÓÃÖмä¼þ¡£

django ÊÓͼº¯Êý²âÊÔµÄÁ½ÖÖ·½·¨¶Ô±ÈºÍÔ­ÀídzÎö

django ÇëÇóµÄ´¦ÀíÁ÷³ÌµÄ´óÖÂÈçÏÂ: ´´½¨ request ¶ÔÏó-->Ö´ÐÐÖмä²ã´¦Àí-->ÊÓͼº¯Êý´¦Àí-->Öмä²ã´¦Àí-->·µ»ØÏçÏìÓ¦¶ÔÏó¡£

ÎÒÃÇ¿ÉÒÔ´ÓÔ´ÂëÖп´³öÀ´:


class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ³õʼ»¯Ê±£¬¼ÓÔØÖмä¼þ
        self.load_middleware()

    def __call__(selfenvironstart_response):# °´ÕÕ WSGI Ð­Òé½ÓÊܲÎÊý
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__environ=environ)
        # ´´½¨ÇëÇó¶ÔÏó£¬Ä¬ÈÏÊÇ WSGIRequest ¶ÔÏó
        request = self.request_class(environ)
        # »ñÈ¡ÏìÓ¦¶ÔÏó£¬get_response Ö´ÐРÖмä¼þ-->ÊÓͼº¯Êý-->Öмä¼þ 
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        # °´ÕÕ wsgi Ð­Òé·µ»ØÊý¾Ý
        start_response(status, response_headers)
        if getattr(response, 'file_to_stream'Noneis not None and environ.get('wsgi.file_wrapper'):
            response = environ['wsgi.file_wrapper'](response.file_to_stream)
        return response

ÎÒÃÇÀ´¿´Ï client µÄºËÐÄÔ´Âë:


# django/test/client.py


class ClientHandler(BaseHandler):

    def __call__(selfenviron):
        # ¼ÓÔØÖмä¼þ
        if self._middleware_chain is None:
            self.load_middleware()

                # ...
        # ¹¹½¨ WSGIRequest ÇëÇó¶ÔÏó
        request = WSGIRequest(environ)
        
        # µ÷ÓÃÖмä¼þ-->ÊÓͼº¯Êý-->Öмä¼þ
        response = self.get_response(request)

        # ....
                # ·µ»ØÏìÓ¦¶ÔÏó
        return response


class Client(RequestFactory):

    def request(self, **request):
        # ...
        # Ä£Äâ wsgi Ð­ÒéµÄ environ ²ÎÊý
        environ = self._base_environ(**request)
                # ....
        try:
            # µ÷ÓàClientHandler
            response = self.handler(environ)
        except TemplateDoesNotExist as e:
           # ....

        # ....
        # ¸øÏìÓ¦¶ÔÏóÌí¼Ó¶îÍâµÄÊôÐԺͷ½·¨£¬ÀýÈç json ·½·¨
        response.client = self
        response.request = request

        # Add any rendered template detail to the response.
        response.templates = data.get("templates", [])
        response.context = data.get("context")

        response.json = partial(self._parse_json, response)

        return response

ÎÒÃÇÀ´¿´Ï RequestFactory µÄºËÐÄÔ´Âë


# django/test/client.py

class RequestFactory:

    def _base_environ(self, **request):
        """
        The base environment for a request.
        """
        # This is a minimal valid WSGI environ dictionary, plus:
        # - HTTP_COOKIE: for cookie support,
        # - REMOTE_ADDR: often useful, see #8551.
        # See https://www.python.org/dev/peps/pep-3333/#environ-variables
        return {
            'HTTP_COOKIE''; '.join(sorted(
                '%s=%s' % (morsel.key, morsel.coded_value)
                for morsel in self.cookies.values()
            )),
            'PATH_INFO''/',
            'REMOTE_ADDR''127.0.0.1',
            'REQUEST_METHOD''GET',
            'SCRIPT_NAME''',
            'SERVER_NAME''testserver',
            'SERVER_PORT''80',
            'SERVER_PROTOCOL''HTTP/1.1',
            'wsgi.version': (10),
            'wsgi.url_scheme''http',
            'wsgi.input': FakePayload(b''),
            'wsgi.errors'self.errors,
            'wsgi.multiprocess'True,
            'wsgi.multithread'False,
            'wsgi.run_once'False,
            **self.defaults,
            **request,
        }

    def request(self, **request):
        "Construct a generic request object."
        # ÕâÀïÖ»ÊÇ·µ»ØÁËÒ»¸öÇëÇó¶ÔÏó
        return WSGIRequest(self._base_environ(**request))

´ÓÔ´ÂëÖдó¼Ò¿ÉÒÔ¿´³ö Client ¼¯³É×Ô RequestFactory Àà¡£

Client ¶ÔÏóͨ¹ýµ÷Óà request ·½·¨À´·¢ÆðÍêÕûµÄÇëÇó: ´´½¨ request ¶ÔÏó-->Ö´ÐÐÖмä²ã´¦Àí-->ÊÓͼº¯Êý´¦Àí-->Öмä²ã´¦Àí-->·µ»ØÏçÏìÓ¦¶ÔÏó¡£

RequestFactory ¶ÔÏóµÄ request ·½·¨Ö»×öÁËÒ»¼þÊ :´´½¨ request ¶ÔÏó £¬ËùÒÔÎÒÃÇÒªÊÖ¶¯ÊµÏÖºóÃæµÄÍêÕû¹ý³Ì¡£

×ܽá

±¾ÕÂÖ÷Òª½éÉÜÁËÈçºÎд django µÄµ¥Ôª²âÊÔ£¬²âÊÔÊÓͼº¯ÊýµÄÁ½ÖÖ·½Ê½ºÍ²¿·ÖÔ´ÂëÆÊÎö£¬ÔÚʵ¼Ê¹¤×÷ÖУ¬ÎÒÃÇͨ³£Ê¹Óà Client À´·½±ã²âÊÔ£¬Óöµ½ÇëÇó¶ÔÏó±È½ÏÌØÊâ»òÕßÖ´ÐÐÁ÷³Ì¸´ÔÓµÄʱºò£¬¾ÍÐèҪͨ¹ý RequestFactory ÕâÖÖ·½Ê½¡£


²ÂÄãϲ»¶£º

Python½Ì³Ì£ºDjango¿ò¼ÜÊÓÆµ½Ì³ÌÏÂÔØ

PythonÊÓÆµ½Ì³Ì£ºDjangoÈëÃÅ

python×ÖµäÈçºÎʹÓÃ?ÓÐÄÄЩӦÓó¡¾°?

pythonÅàѵ¿Î³Ì

0 ·ÖÏíµ½£º
ºÍÎÒÃÇÔÚÏß½»Ì¸£¡
¡¾ÍøÕ¾µØÍ¼¡¿¡¾sitemap¡¿