一杯茶的时间,上手 Django 框架开发 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
huan1043269994
V2EX    Python

一杯茶的时间,上手 Django 框架开发

  •  
  •   huan1043269994 2020-04-18 10:37:26 +08:00 6658 次点击
    这是一个创建于 2077 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我们研发开源了一款基于 Git 进行技术实战教程写作的工具,我们图雀社区的所有教程都是用这款工具写作而成,欢迎 Star

    如果你想快速了解如何使用,欢迎阅读我们的 教程文档哦

    Django 是 Python 社区的两大最受欢迎的 Web 框架之一(另一个是 Flask )。凭借功能强大的脚手架和诸多开箱即用的组件,用 Django 搭建 Web 应用快速而又省力。然而,也正是因为过于强大,想要驾驭它需要花费不少的力气。本文将通过实现一个新闻发布网站带你快速熟悉 Django 框架,让你能够骑上这匹快马,在 Web 开发的战场上尽情驰骋。

    提示

    这篇文章写作时用的是 Django 2.x 版本,发表时已经推出了 3.x 版本。经过笔者测试,在 Python 3.7 的环境下运行 Django 3.x 会出现 admin 无法登录的情形,可以选择降到 Python 3.6 及以下的版本,或安装 Django 2.x 。

    起步

    Django 由 Adrian Holovaty 和 Simon Willison 在 2003 年的秋天写成,并在 2005 年正式发布。他们俩当时为一个新闻报社制作网站,对快速开发有着比较高的需求,并且希望能够在开发的同时也能够让非技术人员为网站添加内容。于是这也使得 Django 具备了两项鲜明的特点:

    • 高度强调可复用性可插拔性,内置大量现成的成熟组件,开发效率极高
    • 自带与数据库联动的后台管理系统,能够在开发的同时创建内容

    Django 的名字取自吉他手 Django Reinhardt,发音为 JANG-goh (谐音“尖狗”),但实际上 Django 的吉祥物是一只长着翅膀的小马。

    在这篇教程中,我们也将向 Django 的起源致敬手把手带你开发一个新闻发布网站,并且可以从后台管理系统中添加新闻,展示到网站首页上。

    预备知识

    本教程假定你已经知道了:

    • 基本的 Python 3 语言知识,包括使用 pip 安装包
    • 了解 HTTP 协议基础知识,浏览器和服务器之间是如何互动的

    学习目标

    读完这篇教程后,你将掌握 Django MTV 框架的精髓:

    • M ( Model ):创建数据模型,并执行数据库迁移
    • T ( Template ):写出基本的 Django 模板,并从视图中传入数据
    • V ( View ):在视图中访问数据库,实现业务逻辑,渲染模板,并接入路由表

    虽然 Django 还有很多知识点,但是理解了 MTV,后面的知识点学习起来也就轻松多啦。

    安装 Django 并启用脚手架

    本文假定你已经安装好了 Python 3 和 pip,那么可以直接用 pip 安装 Django:

    pip install django # 如果你用的是 Python 3.7,请安装 Django 2.2: # pip install django==2.2 

    直接用 pip 在全局安装 Django 的确不是一个很好的做法,用虚拟环境更符合最佳实践。为了减少初学者们的认知负担,在这里就简化了安装过程。熟悉 pipenv 等虚拟环境工具的老司机当然可以自行使用哈。

    安装好 Django 后,我们用 Django 自带的脚手架工具 django-admin 创建项目:

    django-admin startproject django_news cd django_news 

    生成的项目骨架及每个文件的作用如下所示:

    django_news ├── django_news // 项目全局文件目录 │ ├── __init__.py │ ├── settings.py // 全局配置 │ ├── urls.py // 全局路由 │ └── wsgi.py // WSGI 服务接口(暂时不用纠结这个是神马) └── manage.py // 项目管理脚本 

    我们使用 manage.py 来运行开发服务器( Development Server ):

    python manage.py runserver 

    提示

    细心的你会发现出现了一行鲜红色的提示:You have 17 unapplied migration(s)...(省略 n 个字符)。不用担心,我们会在接下来的步骤中详细讲解来龙去脉。

    按照提示,我们通过浏览器访问 localhost:8000,可以看到欢迎界面:

    提示

    Django 开发服务器可以保持开启,并且后面修改代码会自动重新加载,非常方便。后面运行其他命令时,再打开一个终端(命令行)即可。

    一切准备就绪,缰绳已在你手中!

    创建第一个自定义 Django App

    在上一节中我们讲到,Django 是一个高度模块化的框架。具体而言,一个 Django 应用由多个子应用组成,我们一般称之为 App (注意不是我们常说的移动应用 APP,而是 Application 的简写),如下图所示。

    Django App 的类别

    Django App 一般分为三大类(根据来源):

    • 内置:即 Django 框架自带的应用,包括 admin (后台管理)、auth (身份鉴权)、sessions (会话管理)等等
    • 自定义:即用来实现我们自身业务逻辑的应用,这里我们将创建一个新闻展示应用
    • 第三方:即社区提供的应用,数量极其丰富,功能涵盖几乎所有方面,能够大大减少开发成本

    所有的 Django 应用都在 django_news/settings.pyINSTALLED_APPS 列表中定义:

    INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] 

    实现自定义 App

    话不多说,让我们来创建第一个自定义 App,名称为 news:

    python manage.py startapp news 

    生成的 news 应用文件夹结构如下所示:

    news // news 应用目录 ├── __init__.py // 初始化模块 ├── admin.py // 后台管理配置 ├── apps.py // 应用配置 ├── migrations // 数据库迁移文件目录 │ └── __init__.py // 数据库迁移初始化模块 ├── models.py // 数据模型 ├── tests.py // 单元测试 └── views.py // 视图 

    这个子目录里面乍一看好多文件啊!这是因为 Django 始终坚持解耦的原则尽量减少代码之间的耦合,把不相关的代码拆成多个模块,让同一个模块具有内聚性。相信我,等到后面慢慢熟悉之后,你会对每一个模块都了如指掌的。

    实际上,每个 Django App 的组织结构符合 Django 的 MTV 法则Model (模型)+ Template (模板)+ View (视图)。MTV 与大家比较熟悉的 MVC 在思想上非常相似,但是命名有比较大的出入,如下表所示:

    大家熟知的 View,在 Django 里面代表的是业务逻辑,也就是 MVC 中的控制器哦!

    将自定义 App 添加到全局配置

    最后,我们在 settings.py 中将 news 应用加入 INSTALLED_APPS 中:

    # ... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'news', ] 

    至此,我们已经创建了第一个 Django 应用!但是现在这个应用还没有任何内容,我们接下来将逐步完善这个应用。

    理解视图:业务逻辑的编写

    也许你已经注意到,通过访问 localhost:8000/admin 已经可以访问后台管理系统了(虽然会跳转到登录界面)。接下来,我们也希望能够访问到刚才创建的 news 应用。因此,这一步中我们将:

    • 在视图( View )中写一点业务逻辑
    • 接入路由,使其能够被访问

    Django 的路由系统

    Django 的路由系统是由全局路由子应用路由组成。简单来说,根据用户输入的 URL,全局路由表进行匹配并选择正确的子应用路由,再由所选择的子应用路由匹配并选择正确的视图( View )。整个流程如下图所示:

    例如,用户访问 example.com/apple/buy,然后全局路由根据 /apple/buy 先选择 apple 的路由表,再从 apple 路由表中根据 /buy 选择 /buy 路由,然后执行 /buy 对应的 BuyView 视图,返回给用户结果。

    编写第一个视图

    对视图访问的流程大致了解之后,我们就可以开始动手了。首先打开 news/views.py ,写一个简单的视图函数,返回一串 Hello World!:

    from django.http import HttpResponse def index(request): return HttpResponse('Hello World!') 

    上面这个 index 函数可以说是一个最简单的视图函数了,实际大部分应用的视图要比这复杂得多。Django 同时支持基于函数的视图( FBV,Function-based View )和基于类的视图( CBV,Class-based View ),这里显然是 FBV,接收一个 request 请求对象作为参数,返回了一个 HttpResponse 对象。

    将视图接入路由

    接着,我们要让路由系统能够访问到刚才写好的视图函数。因此先实现子应用 news 的路由表,创建 news/urls.py 文件如下:

    from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ] 

    每一个 Django 路由表模块( urls.py )中都约定必须包含一个 urlpatterns 列表用来存放路由映射表。列表中每个元素是一个用 django.urls.path 函数封装好的路由映射,通常接收以下三个参数:

    • route:必须,即实际的访问路由,空字符串等于 /,即空路由
    • view:必须,该路由将要访问的视图
    • name:可选,该路由的名称,方便后续在模板中使用

    我们将刚刚写好的 news 路由表接入全局路由表。由于我们希望新闻能够展示在首页(即通过 / 就能访问,无需 /news),因此 news 应用路由在全局路由中的 URL 是一个空字符串。在 django_news/urls.py 中修改如下:

    from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('news.urls')), ] 

    这里使用 django.urls.include 函数将 news 应用的路由表接入进来,并且 include 函数的参数是路由模块路径的字符串 news.urls,省去了手动 import 的麻烦。

    注意

    添加路由规则时顺序是很重要的,因为在尝试匹配时会按照从上到下的顺序进行,因此应该把最模糊的路由(即空路由)放在最下面。

    如果你开发服务器还在运行(如果没有可以再打开),访问 localhost:8000,就可以看到那一串熟悉的字符了:

    理解模板:网页前端的实现

    上一步中,我们学会了如何实现视图,并将其接入路由配置中,使其能够被用户访问。接下来,我们将实现一个 Django 模板作为网页前端,从而给用户呈现更丰富的内容。

    提示

    如果你有过其他模板(或者类似技术)的开发经验,例如 Jinja 、EJS 或是 JSP 等,对 Django 模板会有一种似曾相识的感觉。如果你不了解什么是模板引擎,也不用担心,简单的理解就是一个可以填充内容、甚至能够加入代码逻辑的类似 HTML 文档,最终会被转换成浏览器能够识别的 HTML 文档。

    Django 模板语言基础

    Django 模板本质上是一个 HTML 文档,只不过通过一些特殊的语法实现数据的填充。这里我们讲解一下最常用的三个语法:

    表达式插值

    最常用的语法,没有之一。通过在一对花括号 {{}} 放入一个表达式,就能够在视图中传入表达式中变量的内容,并最终渲染成包含变量具体内容的 HTML 代码。需要注意的是,所支持的表达式仅支持以下形式(可以自由组合):

    <!-- 单个变量 --> {{ variable }} <!-- 获取字典的键或对象的属性 --> {{ dict.key }} {{ object.attribute }} <!-- 获取列表中的某个元素 --> {{ list.0 }} 

    例如,模板这样写:

    <h1>{{ name }}</h1> <p>{{ news.title }}</p> <p>{{ news.visitors.0 }}</p> 

    如果我们在视图中传入以下上下文字典( Context Dictionary ):

    { 'name': 'Tuture', 'news': { 'title': 'Hello World', 'visitors': ['Tom', 'Marc'], } } 

    那么最终渲染成的 HTML 代码就是:

    <h1>Tuture</h1> <p>Hello World</p> <p>Tom</p> 

    条件语句

    条件语句的定义如下:

    {% if is_true %} <h1>It is true!</h1> {% else %} <h1>It is false!</h1> {% endif %} 

    如果变量 is_true 为真,那么最终渲染出来的就是 <h1>It is true!</h1>,否则就是 <h1>It is false!</h1>。注意:整个条件语句必须{% endif %} 结束,并且 {% else %}可选的。

    循环语句

    循环语句用来在模板上展示任意长的列表内容。其语法如下:

    {% for elem in some_list %} <p>{{ elem }}</p> {% endfor %} 

    如果传入的 some_list['Apple', 'Banana', 'Orange'],那么渲染出的 HTML 代码就是:

    <p>Apple</p> <p>Banana</p> <p>Orange</p> 

    实现第一个 Django 模板

    到了动手时间了,我们先实现第一个 Django 模板。在 news 目录中创建一个 templates 目录,再在 templates 目录中创建一个 news 目录,并在内层的 news 目录中创建 index.html 文件:

    mkdir -p news/templates/news touch news/templates/news/index.html 

    思考

    听上去很麻烦,只创建 news/templates,然后把模板放里面不就好了,为什么还要再创建一个 news 目录?这是由于 Django 的模板查找机制会将所有应用里面的模板全部收集到一起,如果两个模板的名字冲突,就会导致其中一个模板不能被正确访问。如果放在 news 子文件夹里面,就能够通过 news/index.html 访问,通过命名空间的机制避免了冲突。

    模板的代码如下:

    {% if news_list %} <ul> {% for elem in news_list %} <li> <h3>{{ elem.title }}</h3> <p>{{ elem.content }}</p> </li> {% endfor %} </ul> {% else %} <p>暂无新闻</p> {% endif %} 

    这短短几行模板代码却很好地覆盖了我们刚刚讲述的三个模板语法:表达式插值、条件语句和循环语句。如果忘记其中某个地方是什么意思的话,翻上去看看吧!

    完成模板的编写后,我们要在视图中对其进行渲染。打开 news/views.py 文件,修改代码如下:

    from django.shortcuts import render def index(request): cOntext= { 'news_list': [ { "title": "图雀写作工具推出了新的版本", "content": "随随便便就能写出一篇好教程,真的很神奇", }, { "title": "图雀社区正式推出快速入门系列教程", "content": "一杯茶的功夫,让你快速上手,绝无担忧", }, ] } return render(request, 'news/index.html', cOntext=context) 

    这里我们调用 django.shortcuts.render 函数来渲染模板,这个函数通常接受三个参数(有其他参数,但是这里我们不关心):

    • request:请求对象,直接把视图的参数 request 传进来就可以
    • template_name:模板名称,这里就是我们刚刚创建的 news/index.html
    • context:传入模板的上下文对象,必须是一个字典,字典中的每个键对应模板中的变量。这里我们弄了些假数据,假装是从数据库里面取来的。

    再访问 localhost:8000,看一下我们的首页是不是有内容了:

    完美!

    理解模型:和数据库的联动

    Django 的 MTV,我们已经讲了 T ( Template )和 V ( View ),现在来到了最后一关:M ( Model )了。数据模型是 Django 入门最大的难点,消化这一步的内容需要花点力气,但是相信我,当你迈过 M 这最后一关,你便能真正上手 Django 开发了!下面我们先介绍一下 Django 的数据模型设计。

    Django 在数据模型方面的设计堪称典范,列举一些闪光点:

    • 由于高度解耦的设计,可轻松切换各种关系型数据库(默认的 SQLite,可选 MySQL 、PostgreSQL 、Oracle 等等)
    • 强大的 ORM ( Object Relation Mapping,对象关系映射)模块,使得用 Python 操作数据库非常轻松,免去了使用 SQL 的麻烦
    • 优秀的数据库迁移机制( Migration ),修改数据模式( Schema )比较方便,能够适应不断变化的功能需求

    对于初学者而言,我们暂且选择默认的 SQLite 数据库,省去了配置数据库的烦恼。在后面的进阶教程中,我们会切换到其他适合生产环境的数据库。

    理解 ORM

    简单来说,ORM 能够将面向对象的代码转换成相应的 SQL 语句,从而对数据库进行操作。SQL 是用于访问和处理数据库的标准的计算机语言,但是直接写在代码里面显然难以维护,而且对使用者的要求也非常高,写的糟糕的 SQL 代码查询效率非常低下。因此,使用设计良好的 ORM 不仅让代码可读性更好,也能帮助开发者进行查询优化,节省不少力气。

    我们来看一些简单的 Django ORM 例子:

    # 查询所有模型 # 等价于 SELECT * FROM Blog Blog.objects.all() # 查询单个模型 # 等价于 SELECT * FROM Blog WHERE ID=1 Blog.objects.get(id=1) # 添加单个模型 # 等价于 INSERT INTO Blog (title, content) VALUES ('hello', 'world') blog = Blog(title='hello', cOntent='world') blog.save() 

    有木有感觉操作起来比 SQL 方便很多呢?

    理解数据库迁移

    数据库迁移是指将用 Django 定义的模型转换成 SQL 代码(即迁移文件),并在数据库中进行建表操作(或更新表)。看下面这张图就知道了:

    一般的开发流程就是这样:

    1. 用 Django 定义了一个新的数据模型
    2. makemigrations 命令创建迁移文件(存储在子应用的 migrations 目录里面)
    3. migrate 命令执行迁移
    4. 在开发中发现第 1 步中定义的模型不完善,更新数据模型
    5. 跳转到第 2 步,反复循环

    实现第一个数据模型

    终于到了动手的环节。我们首先定义数据模型 Post ,包括标题 title 字段和 content 字段,代码如下:

    from django.db import models class Post(models.Model): title = models.CharField(max_length=200) cOntent= models.TextField() def __str__(self): return self.title 

    定义好之后,运行以下命令创建迁移文件:

    python manage.py makemigrations 

    可以看到输出如下:

    Migrations for 'news': news/migrations/0001_initial.py - Create model Post 

    并且成功地自动创建了 news/migrations/0001_initial.py 迁移脚本。接着我们进行数据库迁移:

    python manage.py migrate 

    输出如下图所示:

    数据库迁移完成后,我们就可以创建用于登录后台管理的超级用户:

    python manage.py createsuperuser 

    按照提示填写用户名和密码即可。然后访问 localhost:8000/admin,进入后台系统的登录页面:

    填入刚才设置的用户名和密码,进入后台管理页面:

    咦,我们刚才创建的 news 应用还有 Post 模型去哪了?

    配置后台管理接口

    那是因为我们没有实现 news 应用的后台管理接口。在 news/admin.py 中填入代码如下:

    from django.contrib import admin from .models import Post admin.site.register(Post) 

    再次进入后台管理系统,可以看到我们的 news 应用和 Post 模型了:

    点击 Posts 一栏的 +Add 按钮,开始添加新闻(内容随意):

    大概添加个两三条新闻就差不多啦。你也可以进一步探索后台管理系统,包括修改新闻、添加用户等等,都可以。

    在视图中添加数据查询

    最后,我们在视图中加入从数据库中查询的代码:

    from django.shortcuts import render from .models import Post def index(request): cOntext= { 'news_list': Post.objects.all() } return render(request, 'news/index.html', cOntext=context) 

    访问网站首页,可以看到刚才在后台管理系统添加的新闻了:

    大功告成!在这篇教程中,我们完成了一个新闻发布网站,并且可以从后台管理系统中添加新闻,最终展示到我们的网站首页上。

    希望这篇教程能够让你对 Django 最重要的一些概念和操作有了基本的了解。Django 还有很多很多的高级玩法,例如数据模型中的高级查询、字段索引、更换数据库等等,模板中的继承机制、内部标签等等,还有视图中如何处理各类请求( POST 、PUT 等),我们会在后续更多教程中逐一为大家讲解,不见不散!

    想要学习更多精彩的实战技术教程?来图雀社区逛逛吧。

    32 条回复    2020-04-27 08:32:56 +08:00
    ShayneWang
        1
    ShayneWang  
       2020-04-18 13:41:38 +08:00   1
    收藏从未停止 学习从未开始
    不管了,先插眼。。
    tmac33
        2
    tmac33  
       2020-04-18 14:40:39 +08:00   2
    django 是个好框架,但 2020 年 web 后端我选 Go 。
    brotherlegend
        3
    brotherlegend  
       2020-04-18 14:47:13 +08:00
    谢谢楼主,我茶刚泡好一大杯。来看看
    imxz
        4
    imxz  
       2020-04-18 15:28:12 +08:00
    不错不错 下次有没有分享一杯茶,上手 flask 的?
    Leigg
        5
    Leigg  
       2020-04-18 16:46:58 +08:00 via Android
    可以可以
    ar414
        6
    ar414  
       2020-04-18 16:52:44 +08:00
    这杯茶有点大杯
    2owe
        7
    2owe  
       2020-04-18 17:38:55 +08:00
    文章内容真不错啊。个人表示知易行难,虽然都了解,但想写得这么深入浅出挺不容易的,感谢分享
    sxfscool
        8
    sxfscool  
       2020-04-18 18:10:41 +08:00 via Android
    项目不错,付出了努力,但是现在用 py 做后端市场很小了吧
    Rxianbei
        9
    Rxianbei  
       2020-04-18 18:23:46 +08:00 via Android
    我尼玛都想着转 go 后端了,现在还学 django
    Leon6868
        10
    Leon6868  
       2020-04-18 18:26:28 +08:00
    话说为什么不用 Flask 呢?感觉 Flask 发挥的空间大一点,也没有找到什么漏洞
    izzy27
        11
    izzy27  
       2020-04-18 18:31:10 +08:00
    先 star 了,最近在学 django
    mimzy
        12
    mimzy  
       2020-04-18 18:42:22 +08:00
    @Leon6868 #10 都可以 我自己现在觉得大而全也挺好

    另外现在社区的活跃度 Django 好很多 https://github.com/django/django/commits/master https://github.com/pallets/flask/commits/master 对异步的支持在 Roadmap 里很明确 https://docs.djangoproject.com/en/dev/releases/3.1/(当然这样的话也可以选 Starlette 和 FastAPI 了)
    1nakaELYBbsXbZxY
        13
    1nakaELYBbsXbZxY  
       2020-04-18 22:46:07 +08:00
    看来是半打的柠檬茶
    dayeye2006199
        14
    dayeye2006199  
       2020-04-19 02:16:55 +08:00
    有个问题:业务逻辑一般放在 view 里面还是 model 里面。我看网上有一些讨论,不少人推荐把复杂的逻辑放在 model 里面,做 fat model,view 只是用来负责做数据展示。LZ 的推荐是放在 view 里面。

    这里面有什么考量吗?
    dayeye2006199
        15
    dayeye2006199  
       2020-04-19 02:22:43 +08:00
    @Leon6868 django 是个全家桶,不用装那么多插件就可以把什么 ORM,验证登录 的活都干了。而且不同的 django 项目之间的代码风格也很一致,有种干一件事用一个方法的意思。

    Flask 支持上述功能需要很多插件,插件之间的差异也比较大,灵活度很高,也导致写法很不一样。

    如果只是需要简单的后端功能, 例如暴露一些纯后端 stateless ML 服务的接口等,Flask 还是很有优势的,开发速度也快,多半一个 PY file 就可以走天下了。django 那么多的功能大部分也都用不上。

    这两个框架文档写的都很好,网上的资料也很全。一般根据业务需求选择比较合适的。
    dayeye2006199
        16
    dayeye2006199  
       2020-04-19 02:27:26 +08:00
    @tmac33 对个人开发者和小团队使用还是挺友好的,毕竟 PY 大家或多或少都懂一些,看看文档就能撸个后端出来了。尤其是对不是专门做这块的工程师,例如搞算法的,或者纯搞 infrastructure (网络,存储,数据库这块的),django 这种全家桶+网上例子特别多的,搞出个后端的原型还是挺快的。
    zxcvsh
        17
    zxcvsh  
       2020-04-19 09:46:37 +08:00 via iPhone
    个人感觉,Django 官网教程不香吗,人家官方中文翻译; flask 纯入门,知乎搜李辉也是途径呀
    royceyong
        18
    royceyong  
       2020-04-19 09:54:32 +08:00
    马克改天再读系列:)
    xiaket
        19
    xiaket  
       2020-04-19 11:25:50 +08:00
    @dayeye2006199 就我 n 年前写 Django 的体验来看, 应该还是要将业务逻辑的主干写到 view 里面, 我不介意一些 model 提供额外的 API 供 view 调用, 这是符合 DRY 原则的. 但是如果是要将本应 view 处理的逻辑全放进 model, 而且只是为一个 view 使用, 那么我不会欣赏这样的做法.
    jmyz0455
        20
    jmyz0455  
       2020-04-19 11:59:46 +08:00
    @zxcvsh 马克,正准备学 Django 。
    楼上说了好多 go 的,现在前景那么好?
    jmyz0455
        21
    jmyz0455  
       2020-04-19 12:03:15 +08:00
    咦,认真看一下是 MTV ?我想学前后端分离,输出 RESTful 接口的那种,不需要界面。我用 postman 实现登陆后 CURD 的操作,比较类似于 MVC
    ysw
        22
    ysw  
       2020-04-20 01:36:07 +08:00
    django 上手容易,精通难
    ysw
        23
    ysw  
       2020-04-20 01:36:41 +08:00
    但是还是赞了
    AllenBigBear
        24
    AllenBigBear  
       2020-04-20 09:25:36 +08:00
    @ShayneWang 有笑到
    huan1043269994
        25
    huan1043269994  
    OP
       2020-04-20 10:05:23 +08:00
    @ysw 谢谢
    huan1043269994
        26
    huan1043269994  
    OP
       2020-04-20 10:06:17 +08:00
    @mmixxia 被你看穿了)逃
    huan1043269994
        27
    huan1043269994  
    OP
       2020-04-20 10:06:44 +08:00
    @2owe 谢谢你!我们会努力写出更加优质的教程哒
    huan1043269994
        28
    huan1043269994  
    OP
       2020-04-20 10:06:57 +08:00
    @ar414 再来一杯
    julyclyde
        29
    julyclyde  
       2020-04-20 10:52:15 +08:00
    最后缺个引流网址啊
    Kobayashi
        30
    Kobayashi  
       2020-04-20 13:42:45 +08:00 via Android
    没价值,基本就是官方文档。
    huan1043269994
        31
    huan1043269994  
    OP
       2020-04-20 14:33:26 +08:00
    @julyclyde 公众号关注一波,谢谢老哥
    dengwen168
        32
    dengwen168  
       2020-04-27 08:32:56 +08:00
    感谢分享。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2785 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 43ms UTC 14:43 PVG 22:43 LAX 06:43 JFK 09:43
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86