ÔÚ 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(self, request):
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(self, request):
"""Óû§µÇ¼"""
# ¿Í»§¶ËµÄÇëÇóÌåÊÇ 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(self, request):
"""Í˳öµÇ¼"""
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(request, user, backend=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__(self, get_response=None):
self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
def process_request(self, request):
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__(self, environ, start_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', None) is 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__(self, environ):
# ¼ÓÔØÖмä¼þ
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': (1, 0),
'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Åàѵ¿Î³Ì