"Lesen des Quellcodes" ist eine der effizientesten Methoden, um das Programmieren zu lernen. Der berühmte Werde ein Hacker (Originaltitel: Wie man ein Hacker wird) sagt auch:
Aber sagen wir einfach, es ist nicht gut für Bücher und Workshop-Kurse. Viele oder vielleicht die meisten Hacker haben auf ihre eigene Weise studiert. Nützlich ist (a) Lesen des Codes und (b) Schreiben des Codes.
Ich habe jedoch das Gefühl, dass es viele Menschen gibt, die oft "Code schreiben", aber nicht sehr gut darin sind, "Code zu lesen". (Es ist oft schwieriger, in Bezug auf die Schwierigkeit zu "lesen" ...) In diesem Artikel werde ich Django lesen, ein wichtiges Webframework von Python, und Ihnen eine Atmosphäre zum Lesen des Quellcodes vermitteln. Ich hoffe, dies erhöht die Anzahl der Personen, die den Open Source Code lesen möchten!
Dieses Mal werden wir als ersten Schritt dem Fluss der klassenbasierten Ansicht folgen.
Ich weiß nicht, wie ich es in Qiitas erstem Beitrag schreiben soll. Wenn also ein Fehler beim Zitieren vorliegt, wäre es hilfreich, wenn Sie in den Kommentaren darauf hinweisen könnten.
Wir werden in der folgenden Umgebung fortfahren. Zum Zeitpunkt des Schreibens (November 2020) ist Django die neueste Version 2.2.17, und Sie müssen sich nicht zu sehr mit der Python-Version befassen, aber dieses Mal werden wir mit 3.8.5 fortfahren. Beim Lesen des Quellcodes wird empfohlen, Ihren bevorzugten Editor oder Ihre Lieblings-IDE zu verwenden, die Tag-Sprünge wie PyCharm und Eclipse verwenden können.
Überprüfen Sie für den Django-Quellcode den Installationsort mit $ python -c" import django; print (django .__ path__) "
oder überprüfen Sie den Installationsort oder Official Repository Ziehen wir aus .17).
$ python --version
Python 3.8.5
$ python -m django --version
2.2.17
Beispielcode: https://github.com/tsuperis/read_django_sample
Ansichten können in beiden Funktionen / Klassen in Django geschrieben werden.
hoge/views.py
from django.http.response import HttpResponse
from django.views import View
def function_based_view(request):
"""Funktionsbasierte Ansicht"""
return HttpResponse('function_based_view')
class ClassBasedView(View):
"""Klassenbasierte Ansicht"""
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'),
]
das ist,
/ func /
zugreifen, wird "function_based_view" unabhängig von der HTTP-Anforderungsmethode zurückgegeben./ cls /
mit GET anfordern, wird "class_based_view GET" zurückgegeben./ cls /
stellen, wird "class_based_view POST" zurückgegeben.Es bedeutet, dass · · · Warum verhalten sich funktionsbasierte Ansichten und klassenbasierte Ansichten unterschiedlich?
Wenn Sie sich zunächst die einfache Funktionsbasisansicht function_based_view
und urls.py ansehen, scheint die Funktion django.urls.path zu sein Es scheint als Ansicht zu fungieren, wenn es im zweiten Argument von path festgelegt ist.
Was ist also mit klassenbasierten Ansichten? Wenn Sie sich urls.py ansehen, werden Sie feststellen, dass der größte Unterschied "as_view ()" ist. Lesen wir von hier aus.
View.as_view()
Geben Sie einen Befehl in den Interpreter ein, um zu sehen, wo er sich befindet, oder verwenden Sie die Tag-Jump-Funktion, um die Klasse direkt zu durchsuchen.
>>> from django.views import View
>>> View.__module__
'django.views.generic.base'
(Django-Installationspfad)/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
Ignorieren Sie diesmal den Dekorateur "classonlymethod".
Erkennen Sie so etwas wie "Klassenmethode" (ein Dekorator, der an eine Methode angehängt ist, die in einer nicht instanziierten Klasse aufgerufen werden kann). Dies ist der Grund, warum Sie "ClassBasedView.as_view ()" anstelle von "ClassBasedView (). As_view ()" schreiben können.
Zurück zur Hauptzeile gibt es zwei Argumente
cls
ist eine Konvention von Klassenmethoden und enthält ClassBasedView
.
Argumente, die mit ** beginnen, wie z. B. "** initkwargs", werden als Schlüsselwortargumente variabler Länge bezeichnet und durch Verwendung beliebiger benannter Argumente als Diktiertypen behandelt.
Wenn Sie beispielsweise "as_view (name =" view ", number = 1)" aufrufen, lautet der Inhalt von initkwargs "{'name": "view", number = 1} ".
>>> def kw(hoge, **kwargs):
... print(f'kwargs: {kwargs}')
...
>>> kw('hoge', name='view', number=123)
kwargs: {'name': 'view', 'number': 123}
Es gibt keine schwierige Verarbeitung, also werde ich knusprig. Es scheint, dass initkwargs (dict-Typ) eine Schleife ist und der Argumentname überprüft wird.
Als Fehlerbedingung
key
(Argumentname) existiert in ClassBasedView.http_method_names
Was ist der http_method_names
von 1?
Es wird am Anfang der View-Klasse definiert.
(Django-Installationspfad)/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']
Das heißt, in dieser Schleife alle Argumentnamen
Ich stellte fest, dass ich nachschaute.
Dies ist das Herz dieser Zeit. Definiert die Ansichtsfunktion. Wenn Sie sich auch den Rückgabewert von "as_view" ansehen, können Sie sehen, dass diese Funktion zurückgegeben wird.
Vergleichen wir die zuvor erstellte funktionsbasierte Ansicht mit der Ansichtsfunktion.
def function_based_view(request):
def view(request, *args, **kwargs):
Da * args
als Argument variabler Länge bezeichnet wird und die Eingabe beliebig ist, ist das einzige erforderliche Argument der Ansichtsfunktion das erste Argument.
Mit anderen Worten, es kann als "function_based_view" bezeichnet werden, sodass es als funktionsbasierte Ansicht verwendet werden kann.
Mal sehen, wie es weitergeht. Ich habe die Klasse instanziiert und dann die "Setup" -Versandmethode aufgerufen.
__init__
sieht so aus.
Ich habe das benannte Argument von "as_view" als Attribut der Instanz festgelegt, aber da ich dieses Mal kein Argument für "as_view" angegeben habe, werde ich es ignorieren.
(Django-Installationspfad)/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)
Hier ist es einfach, also werde ich einfach den Code darauf setzen. Die "self.request", die häufig bei Verwendung der klassenbasierten Ansicht angezeigt wird, wird zu diesem Zeitpunkt festgelegt.
(Django-Installationspfad)/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
enthält buchstäblich den Namen der HTTP-Anforderungsmethode.
Sie versuchen, mit getattr
dieselbe Instanzmethode wie den Namen der HTTP-Anforderungsmethode abzurufen.
Mit anderen Worten
self.get
anself.post
anself.http_method_allowed
anScheint von hier zu kommen.
(Django-Installationspfad)/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) #Hier
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
Ich werde den Verarbeitungsablauf der Ansichtsfunktion kurz zusammenfassen.
self.request`` self.kwargs`` self.args
(D) update_wrapper
Es ist nicht Djangos Code, aber es ist wichtig, wenn Sie originelle Dekorateure erstellen. Deshalb werde ich ihn kurz vorstellen.
console
>>> from functools import update_wrapper
>>> def view():
... """Dies ist die Ansichtsfunktion"""
... pass
...
>>> def dispatch():
... """Dies ist die Versandfunktion"""
... pass
...
>>> view.__doc__
'Dies ist die Ansichtsfunktion'
>>> update_wrapper(view, dispatch)
<function dispatch at 0x7f90328194c0>
>>> view.__doc__
'Dies ist die Versandfunktion'
Das Beispiel sieht so aus, verstehst du?
Wenn Sie die Funktion aufrufen, wird view .__ doc__
durch dispatch .__ doc__
ersetzt.
Zusätzlich zu "doc" gibt es zu überschreibende Attribute, aber im Grunde die Metadaten Es wird als Ersatz verwendet.
In diesem Fall wird es einer neuen Funktion namens view ermöglicht, die Metadaten des Klassenkörpers und der Versandmethode zu erben.
Die einfache Zusammenfassung des Prozesses "as_view" lautet "Erstellen Sie eine Ansichtsfunktion, die die Instanzmethode aufruft, die der HTTP-Anforderungsmethode entspricht."
Ich habe versucht, dem Quellcode in Eile zu folgen, aber als ich ihn tatsächlich gelesen habe
Ich denke, das ist der Punkt. Sie können die detaillierte Verarbeitung verfolgen, aber wenn Sie das Ganze nicht verstehen, wissen Sie nicht, was Sie getan haben.
Ich habe mich nicht besonders entschieden, aber ich werde FormView oder Form lesen. Ich würde auch gerne Model lesen, aber es scheint aufgrund der Metaprogrammierung lang zu sein, also werde ich es versuchen, nachdem ich mich ein bisschen mehr an Qiita gewöhnt habe. .. ..
Ich habe die Fortsetzung geschrieben
Recommended Posts