JavaScript是一種動態、輕量級的腳本語言,在網頁中占據著中心地位。它編排客戶端腳本,利用其解釋性和面向對象的特性精心制作動態用戶交互。想要了解JavaScript的更多知識,可以參加web前端培訓,以獲得快速提升和進步。
Python是編程界的后起之秀,在機器學習、網絡開發和軟件測試等應用領域大放異彩。它的普遍吸引力迎合了開發人員和新手。
Python和JavaScript:Web開發中的前端和后端框架
讓我們探討一下這些語言在網絡開發的前端和后端中是如何發揮不同作用的。無論你是剛開始還是有一些編程經驗,了解Python和JavaScript都可以為創造獨特的在線體驗打開大門。
用于后端的Python:
要開始后端開發之旅,首先要掌握Python本身。了解它的優勢和局限性。然后,深入研究兩個著名的Python框架:Flask和Django。Flask就像一個緊湊版的Python,易于學習和實現——這是一個很好的起點。另一方面,Django雖然更為復雜,但它提供了無與倫比的力量。
用于前端的Python:
對于前端Python編程,PyScript脫穎而出。它是一個基于瀏覽器的框架,結合了Python和HTML,簡化了程序構建。PyScript利用現代web技術提供了一個干凈且可擴展的API,使其非常適合制作用戶界面。
前端JavaScript:
前端JavaScript框架增強了web應用程序的交互性。流行的選擇包括AngularJS,它豐富了web應用程序的HTML;ReactJS,以可重用的UI組件而聞名;jQuery,一個功能豐富的庫;構建應用程序的主干;Ember,是大網絡項目的理想選擇。加web前端培訓是學習JavaScript很有效的方法,碰到問題能夠及時得到解決,大大提高了學習效率。
后端JavaScript:
在后端,JavaScript也大放異彩。像Firebase這樣的框架提供實時數據存儲和同步。Node.js支持構建快速、可擴展的網絡應用程序。PhantomJS提供了可編寫腳本的無頭瀏覽。Express為web應用程序提供了靈活性,而Meteor則支持端到端的JavaScript web開發。
簡而言之:
Python和JavaScript兼顧前端和后端開發。Python簡單明了的框架使其成為首選。對于初學者來說,Python的Flask提供了一個簡單的入口,而Django提供了高級功能。前端框架增強了JavaScript方面的用戶體驗,而后端框架提供了多種功能。最終,你在JavaScript和Python之間的選擇取決于項目的復雜性和個人偏好。
Python與JavaScript:速度與性能的對決
在速度和性能方面,Python和JavaScript占據了中心位置,各自都有獨特的優勢。Python在處理CPU密集型任務方面大放異彩,使其成為復雜計算和處理的可靠選擇。相反,JavaScript通過Node.js提供了多線程功能,為網絡上的動態和實時交互提供了動力。這引發了科技行業關于Node.js與Python后端開發的持續討論。
Python成為了重數據文件處理、CPU密集型項目和大規模應用程序的最終解決方案。開發人員可以通過使用Cython或NumPy等工具優化Python代碼來提高性能。當我們瀏覽錯綜復雜的web開發時,Python和JavaScript提供了獨特的性能優勢,可以滿足各種項目需求。
總結
Python和JavaScript在網絡開發領域站穩了腳跟,各自都有獨特的優勢。當你走上這條編碼之路時,請記住,無論是Python的多功能性還是JavaScript的實時魅力,選擇都會塑造你項目的靈魂。想要掌握Javascript技能和知識,建議參加web前端培訓,課程實時更新,緊跟企業需求,讓你輕松找到工作。
家好,我是小雨。
上一講我們介紹的是:Django框架學習筆記(三)Templates模板 ,我們了解了Django中如何加載html頁面、介紹了模板語言DTL、以及靜態文件的加載。現在頁面已經能正常顯示了,我們希望網頁中的鏈接點擊后能跳轉到指定頁面或者自動重定向該怎么做呢?于是我們今天將要介紹url跳轉的知識。與此同時,實際的網站項目為了便于團隊開發各個模塊有各自獨立的app,我們該怎么做讓各個獨立的app正常工作的同時也互不干擾呢?所以今天也會向大家介紹一下Django中的多app環境的管理。
URL的跳轉是什么呢?URL的跳轉可以稱為URL重定向,表示從一個HTML頁面跳到另外一個頁面。 URL跳轉有兩種途徑:html的<a>標簽和Django的redirect方法
把文本或者圖放到a標簽里,點擊a標簽跳轉。在Django中需要注意的是:html里給href的值為指定路徑名而不是整個包含后綴的html文件。
<li><a href="game/">游戲</a></li>
<li><a href="movie/">電影</a></li>
<li><a href="music/">音樂</a></li>
我們在首頁定義三個超鏈接,分別指向三個頁面
通過a標簽訪問指定頁面
滿足一定條件自動跳轉,常使用redirect關鍵字。某些網站如果你沒有登錄的話它會自動跳轉到登錄頁面。
使用redirect方法進行重定向,首先需要導包:
from django.shortcuts import redirect
在views中定義登陸方法時,我們試著從url中獲取用戶名,如果用戶名存在則訪問首頁,如果不存在則重定向至登陸頁面,這個邏輯代碼就可以這樣寫:
def index(request):
username = request.GET.get("username")
if username:
return render(request, "index.html")
else:
return redirect("/login/")
這樣就能實現的功能是:
用戶想訪問首頁,在沒有登錄的情況下會自動重定向至登錄頁面。但如果系統在url中獲取到用戶名,則打開首頁。
用戶沒登錄則訪問登錄頁面,登錄了則訪問主頁
二、多app項目
在實際的開發過程中,為了減少相互之間的干擾,以及便于團隊之間的同步開發,網站的每一個模塊都部署在不同的app中。這里我們以B站為例,首頁、電影、音樂分別分布在三個app中,分別是home、movie、music,其結構如下:
多app環境
首先使用startapp分別創建home、music、movie三個app;接著在settings.py的INSTALLED_APPS列表中將三個app的名稱添加進來。
INSTALLED_APPS = [
... # 這里省略系統默認添加的app名稱
'home',
'movie',
'music',
]
表明這些app現在已經在我們的項目中登記注冊了,否則后期跨app調用的時候會出現問題。
在每一個app文件夾中都獨立設置urls.py文件,系統urls.py通過include關鍵字對各個app下的urls做統一中轉管理。
我們首先在home下的views中定義一個index方法,使用httpresponse返回字符串“B站首頁”。
from django.http import HttpResponse
def index(request):
return HttpResponse("B站首頁")
接下來在home下新建一個urls.py,將同級目錄下的views導入進來,定義urlpatterns,將首頁路徑添加進來。
from django.urls import path
from . import views
# ====== home下的url ========urlpatterns = [
path("", views.index),
]
最后在項目urls.py中做一個中轉,
from django.urls import path, include
path('', include("home.urls")),
這樣就能成功訪問home下的服務了,我們在此基礎上再完成movie和music的配置。它們的views都可以定義自己的index方法,urls訪問對應的index,只要最后在系統項目urls下對各個模塊做好中轉管理即可。
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("home.urls")),
path('movie/', include("movie.urls")),
path('music/', include("music.urls")),
]
這樣就能訪問各個模塊下的各個服務了,效果演示如下:
在各自的app文件夾下新建一個文件夾templates,記得使用右鍵菜單Mark Directory as Template Folder將文件夾設置為模板文件夾。
我們在home、movie、music各個app下的模板文件夾里新建html頁面。但是注意如果多個app中有模板文件有重名的話,系統就會只訪問第一個模板文件,我們要杜絕這種情況的發生。
在各app下的模板文件夾下再建一個與app同名的文件夾,模板文件就放在這個文件夾里。這樣就可以產生路徑的差異,訪問同名模板文件就不會沖突。
多app環境下模板文件結構
我們在views里的render方法把文件夾名加上即可。
def index(request):
return render(request, 'home/index.html')
多app路徑分析過程為:
以上三步就是多app下url找到模板文件的方法。
多app環境下url訪問邏輯
4. 多app靜態文件管理
多app下訪問靜態文件也是同樣的道理,如果直接訪問同名靜態文件會沖突。我們也是采取同樣的方法在靜態文件夾下再建一個與app同名的子文件夾,來做到路徑的區分。
多app環境下靜態文件的布置
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'home', 'static'),
os.path.join(BASE_DIR, 'movie', 'static'),
os.path.join(BASE_DIR, 'music', 'static'),
]
讓系統找到每個app下的static文件夾即可。
<img src="{% static '/home/img/pic.png' %}">
多app環境下分別訪問主頁、音樂、電影頁面
以上,我們就完成了url重定向與多app下模板文件與靜態文件的管理。下一節,我們繼續介紹Django相關知識~
希望能點個贊支持一下~
非常感謝大家的閱讀!
?
//E:\Go\src\net\http\server.go +82
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
//純 net.http包的server方法
package main
import (
"io"
"net/http"
)
type helloHandler struct{}
func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))
}
func main() {
http.Handle("/", &helloHandler{})
http.ListenAndServe(":12345", nil)
}
//////////////////////////////////////////////////////////////////
import (
"net/http"
)
type Handle struct{}
func (h Handle) ServeHTTP(response http.ResponseWriter, request *http.Request) {
switch request.URL.Path {
case "/info":
response.Write([]byte("info"))
default:
}
}
func main() {
http.ListenAndServe(":8888", Handle{})
}
//gin框架初始化的流程
1.初始化engine
2.注冊中間件
3.注冊路由
//響應流程
1.路由,找到handle
2.將請求和響應用Context包裝起來供業務代碼使用
3.依次調用中間件和處理函數
4.輸出結果
//gin 里面最重要的兩個數據結構
//1.Context在中間件中傳遞本次請求的各種數據、管理流程,進行響應
//2.Engine gin 引擎,是框架的實例,它包含多路復用器,中間件和配置設置
// 下面看下open-falcon-api中的實際應用
//open-falcon-api里面注冊路由和中間件
//E:\go_path\src\github.com\open-falcon\falcon-plus\modules\api\app\controller\graph\graph_routes.go
// 首先注冊/api/v1/開頭的path的路由組
// 然后Use 一個auth的中間件 ,作用是檢查token
// 這個組后面的所有path 都使用這個中間件
// 也就是訪問 /graph/endpoint 時會過 3個中間件(log recovery auth )+一個EndpointRegexpQuery處理函數
//
func Routes(r *gin.Engine) {
db=config.Con()
authapi :=r.Group("/api/v1")
authapi.Use(utils.AuthSessionMidd)
authapi.GET("/graph/endpointobj", EndpointObjGet)
authapi.GET("/graph/endpoint", EndpointRegexpQuery)
authapi.GET("/graph/endpoint_counter", EndpointCounterRegexpQuery)
authapi.POST("/graph/history", QueryGraphDrawData)
authapi.POST("/graph/lastpoint", QueryGraphLastPoint)
authapi.POST("/graph/info", QueryGraphItemPosition)
authapi.DELETE("/graph/endpoint", DeleteGraphEndpoint)
authapi.DELETE("/graph/counter", DeleteGraphCounter)
grfanaapi :=r.Group("/api")
grfanaapi.GET("/v1/grafana", GrafanaMainQuery)
grfanaapi.GET("/v1/grafana/metrics/find", GrafanaMainQuery)
grfanaapi.POST("/v1/grafana/render", GrafanaRender)
grfanaapi.GET("/v1/grafana/render", GrafanaRender)
}
func AuthSessionMidd(c *gin.Context) {
auth, err :=h.SessionChecking(c)
if !viper.GetBool("skip_auth") {
if err !=nil || auth !=true {
log.Debugf("error: %v, auth: %v", err, auth)
c.Set("auth", auth)
h.JSONR(c, http.StatusUnauthorized, err)
c.Abort()
return
}
}
c.Set("auth", auth)
}
// E:\go_path\src\github.com\open-falcon\falcon-plus\vendor\github.com\gin-gonic\gin\context.go +715 最后會調用這里的Render方法
// Render writes the response headers and calls render.Render to render data.
func (c *Context) Render(code int, r render.Render) {
c.Status(code)
if !bodyAllowedForStatus(code) {
r.WriteContentType(c.Writer)
c.Writer.WriteHeaderNow()
return
}
if err :=r.Render(c.Writer); err !=nil {
panic(err)
}
}
// 可以看到這里的bind 是在gin在解析請求payload是否和函數中要求的struct一致
// E:\go_path\src\github.com\open-falcon\falcon-plus\vendor\github.com\gin-gonic\gin\context.go +504
// bind會根據請求中的Content-Type header判斷是json 還是xml
// 并且根據struct中的tag通過反射解析payload
// Bind checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used:
// "application/json" --> JSON binding
// "application/xml" --> XML binding
// otherwise --> returns an error.
// It parses the request's body as JSON if Content-Type=="application/json" using JSON or XML as a JSON input.
// It decodes the json payload into the struct specified as a pointer.
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
func (c *Context) Bind(obj interface{}) error {
b :=binding.Default(c.Request.Method, c.ContentType())
return c.MustBindWith(obj, b)
}
type APIEndpointObjGetInputs struct {
Endpoints []string `json:"endpoints" form:"endpoints"`
Deadline int64 `json:"deadline" form:"deadline"`
}
func EndpointObjGet(c *gin.Context) {
inputs :=APIEndpointObjGetInputs{
Deadline: 0,
}
if err :=c.Bind(&inputs); err !=nil {
h.JSONR(c, badstatus, err)
return
}
if len(inputs.Endpoints)==0 {
h.JSONR(c, http.StatusBadRequest, "endpoints missing")
return
}
var result []m.Endpoint=[]m.Endpoint{}
dt :=db.Graph.Table("endpoint").
Where("endpoint in (?) and ts >=?", inputs.Endpoints, inputs.Deadline).
Scan(&result)
if dt.Error !=nil {
h.JSONR(c, http.StatusBadRequest, dt.Error)
return
}
endpoints :=[]map[string]interface{}{}
for _, r :=range result {
endpoints=append(endpoints, map[string]interface{}{"id": r.ID, "endpoint": r.Endpoint, "ts": r.Ts})
}
h.JSONR(c, endpoints)
}
//E:\go_path\src\github.com\open-falcon\falcon-plus\modules\api\main.go +78
//初始化gin
routes :=gin.Default()
//E:\go_path\src\github.com\open-falcon\falcon-plus\vendor\github.com\gin-gonic\gin\gin.go +148
// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
debugPrintWARNINGDefault()
engine :=New()
engine.Use(Logger(), Recovery())
return engine
}
//E:\go_path\src\github.com\open-falcon\falcon-plus\vendor\github.com\gin-gonic\gin\gin.go +119
// new方法 返回一個不帶中間件的 單例engine ,并且把context 放在池中
func New() *Engine {
debugPrintWARNINGNew()
engine :=&Engine{
RouterGroup: RouterGroup{
Handlers: nil,
basePath: "/",
root: true,
},
FuncMap: template.FuncMap{},
RedirectTrailingSlash: true,
RedirectFixedPath: false,
HandleMethodNotAllowed: false,
ForwardedByClientIP: true,
AppEngine: defaultAppEngine,
UseRawPath: false,
UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory,
trees: make(methodTrees, 0, 9),
delims: render.Delims{Left: "{{", Right: "}}"},
secureJsonPrefix: "while(1);",
}
engine.RouterGroup.engine=engine
engine.pool.New=func() interface{} {
return engine.allocateContext()
}
return engine
}
//E:\go_path\src\github.com\open-falcon\falcon-plus\modules\api\app\controller\routes.go
//r.Run(port) 最后調用的是 net.http.ListenAndServe
func (engine *Engine) Run(addr ...string) (err error) {
defer func() { debugPrintError(err) }()
address :=resolveAddress(addr)
debugPrint("Listening and serving HTTP on %s\n", address)
err=http.ListenAndServe(address, engine)
return
}
//E:\Go\src\net\http\server.go +2686
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler :=sh.srv.Handler
if handler==nil {
handler=DefaultServeMux
}
if req.RequestURI=="*" && req.Method=="OPTIONS" {
handler=globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
//E:\go_path\src\github.com\open-falcon\falcon-plus\vendor\github.com\gin-gonic\gin\gin.go +321
//我們可以看到 在gin中實現了ServeHTTP方法 net.http.Handler
// ServeHTTP conforms to the http.Handler interface.
// 這里使用sync.pool cache context數據結構,避免頻繁GC,每次使用都初始化
//一個struct實現了 interface中的方法 就說明這個struct是這個類型
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c :=engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request=req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}
// gin 里面處理請求的核心方法
// 根據一些配置去 壓縮前綴樹 radix.tree中找到對應的handleChain 然后執行
// 注意這句handlers, params, tsr :=root.getValue(path, c.Params, unescape)
// 路由查找的過程是 從基數樹的根節點一直匹配到和請求一致的節點找到對應的handlerchain
// 注冊路由 E:\go_path\src\github.com\open-falcon\falcon-plus\vendor\github.com\gin-gonic\gin\gin.go +243
// 從下面的addRoute方法中可以看到gin 為每個HttpMethod GET POST PUT DELETE都注冊了一顆tree
// 并且有priority 即最長的路徑優先匹配
/*
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
assert1(path[0]=='/', "path must begin with '/'")
assert1(method !="", "HTTP method can not be empty")
assert1(len(handlers) > 0, "there must be at least one handler")
debugPrintRoute(method, path, handlers)
root :=engine.trees.get(method)
if root==nil {
root=new(node)
engine.trees=append(engine.trees, methodTree{method: method, root: root})
}
root.addRoute(path, handlers)
}
*/
func (engine *Engine) handleHTTPRequest(c *Context) {
httpMethod :=c.Request.Method
path :=c.Request.URL.Path
unescape :=false
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
path=c.Request.URL.RawPath
unescape=engine.UnescapePathValues
}
// Find root of the tree for the given HTTP method
t :=engine.trees
for i, tl :=0, len(t); i < tl; i++ {
if t[i].method !=httpMethod {
continue
}
root :=t[i].root
// Find route in tree
handlers, params, tsr :=root.getValue(path, c.Params, unescape)
if handlers !=nil {
c.handlers=handlers
c.Params=params
c.Next()
c.writermem.WriteHeaderNow()
return
}
if httpMethod !="CONNECT" && path !="/" {
if tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c)
return
}
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
return
}
}
break
}
if engine.HandleMethodNotAllowed {
for _, tree :=range engine.trees {
if tree.method==httpMethod {
continue
}
if handlers, _, _ :=tree.root.getValue(path, nil, unescape); handlers !=nil {
c.handlers=engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
}
}
}
c.handlers=engine.allNoRoute
serveError(c, http.StatusNotFound, default404Body)
}
*請認真填寫需求信息,我們會在24小時內與您取得聯系。