Afficher la version ② FormView
"Lire le code source" est l'un des moyens efficaces d'apprendre la programmation. Le célèbre Become a Hacker (titre original: How To Become A Hacker) dit également:
Mais disons simplement que ce n'est pas bon pour les livres et les cours en atelier. De nombreux hackers, voire la plupart, ont étudié à leur manière. Il est utile (a) de lire le code et (b) d'écrire le code.
Cependant, j'estime qu'il y a beaucoup de gens qui "écrivent souvent du code" mais ne sont pas très doués pour "lire du code". (Il est souvent plus difficile de "lire" en termes de difficulté ...) Dans cet article, je vais lire Django, un framework web majeur de Python, et vous donner une atmosphère de lecture du code source. J'espère que cela augmentera le nombre de personnes souhaitant lire le code open source!
Cette fois, comme première étape, nous suivrons le flux de la vue basée sur les classes.
Je ne sais pas comment l'écrire dans le premier message de Qiita, donc si vous faites une erreur en citant, il serait utile que vous puissiez le signaler dans les commentaires.
Nous procéderons dans l'environnement suivant. Au moment de la rédaction de cet article (novembre 2020), Django est le dernier 2.2.17, et vous n'avez pas besoin d'être trop précis sur la version Python, mais cette fois, nous allons procéder avec 3.8.5. Lors de la lecture du code source, il est recommandé d'utiliser votre éditeur ou IDE préféré qui peut utiliser des sauts de balises tels que PyCharm et Eclipse.
Pour le code source de Django, vérifiez l'emplacement d'installation avec $ python -c" import django; print (django .__ path__) "
, ou vérifiez l'emplacement d'installation ou Official Repository Tirons de .17).
$ python --version
Python 3.8.5
$ python -m django --version
2.2.17
--Comment comprendre Python 3.x --Comment comprendre le [Tutoriel] de Django (https://docs.djangoproject.com/ja/2.2/intro/)
Exemple de code: https://github.com/tsuperis/read_django_sample
Les vues peuvent être écrites dans les deux fonctions / classes de Django.
hoge/views.py
from django.http.response import HttpResponse
from django.views import View
def function_based_view(request):
"""Vue basée sur les fonctions"""
return HttpResponse('function_based_view')
class ClassBasedView(View):
"""Vue basée sur les classes"""
def get(self, request):
return HttpResponse('class_based_view GET')
def post(self, request):
return HttpResponse('class_based_view POST')
core/urls.py
from django.urls import path
from hoge import views as hoge_views
urlpatterns = [
path('func/', hoge_views.function_based_view, name='hoge_func'),
path('cls/', hoge_views.ClassBasedView.as_view(), name='hoge_cls'),
]
c'est,
--Lorsque vous accédez à / func /
, "function_based_view" est renvoyé quelle que soit la méthode de requête HTTP.
--Lorsque vous demandez / cls /
avec GET, "class_based_view GET" est renvoyé.
--Lorsque vous faites une requête POST à / cls /
, "class_based_view POST" est renvoyé.
/ cls /
autre que GET / POST, la méthode non autorisée avec l'état HTTP 405 est renvoyée.Cela signifie que · · · Pourquoi les vues basées sur les fonctions et les vues basées sur les classes se comportent-elles différemment?
Tout d'abord, si vous regardez la vue de base de fonction simple function_based_view
et urls.py, il semble que la fonction soit [django.urls.path](https://docs.djangoproject.com/en/2.2/ref/urls/# Il semble fonctionner comme une vue s'il est défini dans le deuxième argument de chemin).
Alors qu'en est-il des vues basées sur la classe?
Si vous regardez urls.py, vous remarquerez que la plus grande différence est as_view ()
.
Lisons d'ici.
View.as_view()
Tapez une commande dans l'interpréteur pour voir où elle se trouve, ou utilisez la fonction de saut de balise pour parcourir la classe directement.
>>> from django.views import View
>>> View.__module__
'django.views.generic.base'
(chemin d'installation de django)/django/views/generic/base.py
# -- (A)
@classonlymethod
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
# -- (B)
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
# -- (C)
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# -- (D)
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
Ignorez cette fois le décorateur classonlymethod
.
Reconnaissez quelque chose comme classmethod
(un décorateur attaché à une méthode qui peut être appelée dans une classe non instanciée).
C'est la raison pour laquelle vous pouvez écrire ClassBasedView.as_view ()
au lieu de ClassBasedView (). As_view ()
.
Pour revenir à la ligne principale, il y a deux arguments
cls
est une convention de méthodes de classe et contient ClassBasedView
.
Les arguments qui commencent par , tels que « initkwargs», sont appelés arguments de mot-clé de longueur variable et sont traités comme des types de dict en prenant des arguments nommés arbitraires.
Par exemple, si vous appelez as_view (name = 'view', number = 1)
, le contenu de initkwargs sera {'name': 'view', number = 1}
.
>>> def kw(hoge, **kwargs):
... print(f'kwargs: {kwargs}')
...
>>> kw('hoge', name='view', number=123)
kwargs: {'name': 'view', 'number': 123}
Il n'y a pas de traitement difficile, donc je vais devenir croustillant. Il semble que initkwargs (type dict) soit en boucle et que le nom de l'argument soit vérifié.
Comme condition d'erreur
key
(nom de l'argument) existe dans ClassBasedView.http_method_names
key
n'existe pas dans les attributs de la classe ClassBasedView
Quel est le http_method_names
de 1?
Il est défini au début de la classe View
.
(chemin d'installation de django)/django/views/generic/base.py
class View:
"""
Intentionally simple parent class for all views. Only implements
dispatch-by-method and simple sanity checking.
"""
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
Autrement dit, dans cette boucle tous les noms d'argument
as_view
, http_method_names
J'ai constaté que je vérifiais.
C'est le cœur de cette époque.
Définit la fonction d'affichage. Si vous regardez également la valeur de retour de as_view
, vous pouvez voir que cette fonction est retournée.
Comparons la vue basée sur la fonction créée précédemment avec la fonction de vue.
def function_based_view(request):
def view(request, *args, **kwargs):
Puisque * args
est appelé un argument de longueur variable et que l'entrée est arbitraire, le seul argument requis de la fonction de vue est le premier argument.
En d'autres termes, il peut être appelé comme function_based_view
, donc il peut être utilisé comme une vue basée sur une fonction.
Voyons la suite.
J'ai instancié la classe puis appelé la méthode setup`` dispatch
.
«init» ressemble à ceci.
J'ai défini l'argument nommé de as_view
comme attribut de l'instance, mais comme je n'ai pas spécifié d'argument pour as_view
cette fois, je l'ignorerai.
(chemin d'installation de django)/django/views/generic/base.py
def __init__(self, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in kwargs.items():
setattr(self, key, value)
C'est facile ici, donc je vais juste mettre le code dessus.
Le self.request
, qui est souvent vu lors de l'utilisation de la vue basée sur les classes, est défini à ce moment.
(chemin d'installation de django)/django/views/generic/base.py
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
self.request = request
self.args = args
self.kwargs = kwargs
request.method
contient littéralement le nom de la méthode de requête HTTP.
Vous essayez d'obtenir la même méthode d'instance que le nom de la méthode de requête HTTP avec getattr
.
En d'autres termes
--Lorsque vous demandez / cls / avec GET, "class_based_view GET" est renvoyé.
--Appeler self.get
--Lorsque vous faites une requête POST vers / cls /, "class_based_view POST" est renvoyé.
--Appeler self.post
self.http_method_allowed
Semble venir d'ici.
(chemin d'installation de django)/django/views/generic/base.py
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed) #ici
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
Je résumerai brièvement le flux de traitement de la fonction d'affichage.
self.request`` self.kwargs`` self.args
(D) update_wrapper
Ce n'est pas le code de Django, mais c'est important lors de la création de décorateurs originaux, je vais donc le présenter brièvement.
console
>>> from functools import update_wrapper
>>> def view():
... """C'est la fonction d'affichage"""
... pass
...
>>> def dispatch():
... """C'est la fonction d'expédition"""
... pass
...
>>> view.__doc__
'C'est la fonction d'affichage'
>>> update_wrapper(view, dispatch)
<function dispatch at 0x7f90328194c0>
>>> view.__doc__
'C'est la fonction d'expédition'
L'exemple ressemble à ceci, comprenez-vous?
Lorsque vous appelez la fonction, view .__ doc__
est remplacé par dispatch .__ doc__
.
En plus de __doc__
, il y a Attributs à écraser, mais essentiellement les métadonnées Il est utilisé en remplacement.
Dans ce cas, il est utilisé pour permettre à une nouvelle fonction appelée view d'hériter des métadonnées du corps de la classe et de la méthode dispatch
.
Un simple résumé du processus as_view
est" Créer une fonction de vue qui appelle la méthode d'instance correspondant à la méthode de requête HTTP. "
J'ai essayé de suivre le code source à la hâte, mais quand je l'ai lu
--Lire après avoir confirmé l'opération réelle ――Pour les parties qui ne sont pas liées à la ligne principale, jetez un coup d'œil au nom et au contenu de la fonction pour en avoir une idée.
Je pense que c'est le point. Vous pouvez suivre le traitement détaillé, mais si vous ne comprenez pas tout, vous ne saurez pas ce que vous faisiez.
Je n'ai pas décidé en particulier, mais je vais lire FormView ou Form. J'aimerais aussi lire Model, mais cela semble long à cause de la métaprogrammation, je vais donc l'essayer après m'être habitué un peu plus à Qiita. .. ..
J'ai écrit la suite
Afficher la version ② FormView
Recommended Posts