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小时内与您取得联系。