前导工作:参见后端开发三步曲之二-python-django-基于docker的项目开发
Django后端精要:最简DEMO
每次新建一个页面(应用),常规操作都是
1,setting注册APP,
2,urls设置路由使得服务器可以找到新的页面(urls用于调用views中函数),
3,views当请求request来的时候可以返回页面到前端(views中函数用于HttpReponse或renderHTML模板,数据操作用Model和ORM,也可直接操作数据库)
一、从第一个django项目myPrj和应用myApp开始
按前一步骤配置和初始化好项目,PyCharm的Terminal窗口中测试运行通过,然后CTRL+C结束。
docker-compose up
开一个终端进入容器可进行管理项目:
docker exec -it myapp_container /bn/bash
cd /myapp
保持该终端待用。
在主目录中Pycharm建立新的Python package:Apps,将新建立的myapp移进该目录统一管理
在主项目settings.py中修改搜索路径
import sys
# ...
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 在前面一行后加下以下内容
sys.path.insert(0, os.path.join(BASE_DIR, 'Apps'))
#在INSTALLED_APPS列表中加入Apps.myApp
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Apps.myApp',
]
建立第一个基于模板的应用,项目settings.py中加入模板搜索路径
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
编写一个测试模板index.html放入templates目录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>myapp demo</title>
</head>
<body>
<div>
<h1>Hello, friend from {{ user_ip }} </h1>,<br />
<a href="/list">Click Here to show article list.</a>
</div>
</body>
</html>
修改Apps.myApp下的views.py,增加两个函数:
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return render(request, 'index.html') # 用模板渲染
def hello(request):
return HttpResponse('Hello world!') # 不用模板也能干
生成myApp本地路由,在myApp目录下生成新的urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('hello/', views.hello),
]
在全局路由中引用该局部路由:
from django.contrib import admin
from django.urls import path
# from Apps.myApp import views # 有局部路由引用则不需要了
from django.urls import include # 引用urls的相关包
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('Apps.myApp.urls')), # 引用局部路由
# path('', views.index), # 也可以直接设置全局路由
# path('hello/', views.hello) # 也可以直接设置全局路由
]
!用到再学,路由:path,re_path,url支持的通配模式,以及参数化url传递给views处理函数
二、使用模型和后台管理模型
更改Apps/myApp/models.py,主要作用是对数据库做修改
from django.db import models
from django.utils import timezone
class Article(models.Model):
author = models.ForeignKey('auth.User',on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
打开 Apps/myApp/admin.py 文件,修改为:
from django.contrib import admin
from .models import Article
admin.site.register(Article)
进入容器内部,在之前打开的终端(容器内)中:
# 创建superuser
python manage.py createsuperuser
# 如:root/Root123456
更新model到数据库
python manage.py makemigrations myApp
python manage.py migrate myApp
可以通过http://0.0.0.0:8080/admin/登录并在站点管理中看到用户及MYAPP应用的Articles表(模型)管理界面
三、用视图连接模型与模板
1、显示列表页
1)建立列表页的路由
每一个新的应用都需要在urls.py中注册路由修改Apps/myApp/urls.py 文件。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('hello/', views.hello),
path('list/', views.article_list),
]
2)视图方法,Django ORM 和 QuerySets(查询集)
在Apps/myApp/views.py中修改
from django.shortcuts import render
from django.utils import timezone
from .models import Article
# ...
def article_list(request):
#按时间顺序排列
posts = Article.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'article_list.html', {'posts': posts})
3)Django模板,嵌套层级
在myApp应用的目录下创建一个名为 static 的文件夹,在新建一个css文件夹,设计一个my.css
在templates目录创建基础模板base.html
<!DOCTYPE html>
{% load staticfiles %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>myapp articles</title>
<link rel="stylesheet" href="{% static 'css/my.css' %}">
</head>
<body>
<div>
<h1><a href="/">Home</a></h1>
{% block content %}
{% endblock %}
</div>
</body>
</html>
创建article_list.html扩展基础模板
{% extends 'base.html' %}
{% block content %}
<!-- 只有管理员才能发贴 -->
{% if user.is_authenticated %}
<a href="{% url 'new' %}">Click here to post new article</a>
{% endif %}
<!-- 只有管理员才能发贴 -->
{% for post in posts %}
<div>
<h1>{{ post.title }}</h1>
<p>published: {{ post.published_date }}</p>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock %}ock %}
2、表单页,用于提交数据
1)建立路由,urls.py中添加
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('hello/', views.hello),
path('list/', views.article_list),
path('new/', views.article_new, name='new'), # 起名字,在模板语言中可以用url 'new'引用
]
2)视图处理
表单,创建一个文件forms.py放在myApp目录下。
from django import forms
from .models import Article
class PostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'text',)
修改views.py
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import timezone
from .models import Article
from .forms import PostForm
#...
def article_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return HttpResponseRedirect('/list')
else:
form = PostForm()
return render(request, 'article_new.html', {'form': form})
3)模板article_new.html
{% extends 'base.html' %}
{% block content %}
<h1>New Article</h1>
<form method="POST" class="post-form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}
四、使用Django RESTful Framework做API
1、Serializers
要定义序列化器。创建一个名为myApp/serializers.py的新模块。目前这部分是个黑箱还没有研究,以下代码似乎可以正常运行:
from django.contrib.auth.models import User, Group
from .models import Article
from rest_framework import serializers
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['title', 'text', 'author']
class UserSerializer(serializers.ModelSerializer):
articles = ArticleSerializer(many=True, read_only=True)
class Meta:
model = User
fields = ['url', 'username', 'email', 'groups', 'articles']
class GroupSerializer(serializers.ModelSerializer):
users = serializers.StringRelatedField(many=True)
class Meta:
model = Group
fields = ['url', 'name', 'users']
2、Views
打开myApp/views.py新增代码:
########################################################################
# 以下为RESTful framework所用
from rest_framework import viewsets
from django.contrib.auth.models import User, Group
from .serializers import ArticleSerializer, UserSerializer, GroupSerializer
class UserViewSet(viewsets.ModelViewSet):
""" API endpoint that allows users to be viewed or edited. """
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
""" API endpoint that allows groups to be viewed or edited. """
queryset = Group.objects.all()
serializer_class = GroupSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all().order_by('-published_date')
serializer_class = ArticleSerializer
不是分开写多个视图,分组所有常见的行为成称为 ViewSets 的类。可以把这些分成单个的views, 但使用viewsets可保持视图逻辑很好地组织以及非常简洁。
3、路由url
设置API URLs路由到myPrj/urls.py...
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
router.register(r'articles', views.ArticleViewSet)
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('Apps.myApp.urls')),
# path('', views.index),
path('api/', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
使用viewsets代替views,可以通过用一个路由类注册viewsets为API自动生成URL conf。
同时如果对API URLs需要更多的控制,可以简单地使用常规的views并明确地写URL conf。
这里为browsable API包含了默认的登入登出veiws,这是可选的,但对于Browsable API需要认证时很有用。
4、分页
每个页面分页允许控制多少个对象返回。它添加以下行到settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
5、配置Settings
添加 'rest_framework' to INSTALLED_APPS.。设置settings.py
INSTALLED_APPS = [ ... 'rest_framework',]
6、测试API(容器内,容器外使用8080端口)
$ curl -H 'Accept: application/json; indent=4' -u root:Root123456 http://127.0.0.1:8000/api/articles/
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"title": "test4",
"text": "test4",
"author": 1
},
{
"title": "test3",
"text": "test3",
"author": 1
},
{
"title": "test2",
"text": "test2",
"author": 1
},
{
"title": "test1",
"text": "test1",
"author": 1
},
{
"title": "test6",
"text": "test6",
"author": 1
}
]
}
或直接通过浏览器,通过访问URLhttp://127.0.0.1:8080/api/articles/.(容器外部)..
五、使用git做版本控制
$ git init
Initialized empty Git repository in ~/djangogirls/.git/#建立git仓库
$ git config --global user.name "Your Name"
$ git config --global user.email you@example.com
建立.gitignore文件用于git忽略一些文件
*.pyc
__pycache__
myvenv
db.sqlite3
mysql_data
可以使用git status来查看
然后做添加并确认准备上传到github的文件
$ git add --all .
$ git commit -m "My Django app, first commit"
创建gitee仓库myApp(不要初始化否则与本地不同步),拷贝github仓库接口 https://gitee.com/njbinbin/myApp.git
连接本地git仓库和github仓库,上传本地git仓库代码到github仓库使用push
连接本地git仓库和github仓库
$ git remote add origin https://gitee.com/njbinbin/myApp.git
上传本地git仓库到github仓库
$ git push -u origin master
# 后续更新仓库
git status
git add --all .
# 绿色显示准备上传文件
git status
git commit -m "Some messages."
# 上传到github仓库
git push
六、小结
面向任务完成的工作,面对两个庞大的框架,其实完全不了解其ORM,Serializer的机制,凭网上几个例子去猜丢什么样的代码进去会生成什么样的数据库结构,吐出来什么样的JSON。框架的学习比语言本身要难多了,尤其是不知道设计者的思想,不知道其创造出来的各种新术语,借用的各种模式目的是解决什么问题。而从quickstart开始的文档和网上各种文章,往往就是人云亦云地丢一段代码证明跑通了这个任务。动不动就Talk is cheap, show me the code。。。我倒是觉得多些Talk剖析一下原理与设计思路,比秀一段能跑的代码强得多。
另外,上面的例子只能证明框架按基本的模式可以运行了,认证和安全性相关的机制也没有考虑,因为我还没看到那么细的资料。这个DEMO不能作为一个新项目的起点。
有时间研究下Flask,据说相对简洁。