Django 入门笔记

WSGI

WSGI:(Web Server Gateway Interface We,Web 服务端网关接口)。在不借助框架的情况下,直接使用 WSGI 来开发简易服务端。

# hello.py
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')]) # 设置 Header
return [b'<h1>Hello, web!</h1>'] # 响应内容
# server.py
# 从 wsgiref 模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的 application 函数:
from hello import application

# 创建一个服务器,IP 地址为空,端口是 8000,处理函数是 application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 开始监听 HTTP 请求:
httpd.serve_forever()

运行:python3 server.py

[21:32:30] ~/workspace/demo ❱❱❱ python3 server.py
Serving HTTP on port 8000...

http://localhost:8000/

image-20201116213322503

macOS 安装 Django

Python 版本与 Django 版本的关系

安装 Django 1.11,对应 Python2:

$ sudo python -m pip install Django

安装最新版 Django 3.1,对应 Python3:

$ python3 -m pip install Django

查看版本:

$ python -m django --version
$ python3 -m django --version

创建 Django 项目

创建一个名为 mysite 的 Django 项目

$ django-admin startproject mysite

在没有安装 1.11 版本的 Django 时,提示未找到命令:zsh: command not found: django-admin

解决方式:使用 python3 -m django 替代 django-admin

$ python3 -m django startproject mysite

原因:因为 Python3 不是 macOS 默认的 Python 版本,系统将去 Python2 目录找此命令,找不到。安装 Django 1.11 后,此命令可以使用

  • 命令关键字:startproject

mysite 结构:

mysite/
manage.py # 项目管理
mysite/ # 包名
__init__.py # 作为 Python 包的标记
settings.py # 项目设置
urls.py # 相当于 Spring 的 Controller
asgi.py
wsgi.py

启动项目:

$ python3 manage.py runserver
$ python manage.py runserver 8001
  • runserver:Django 根据 manage.py 后的参数来启动

查看是否启动成功:

http://127.0.0.1:8000/
http://127.0.0.1:8001/

创建投票应用

$ python3 manage.py startapp polls
$ python manage.py startapp polls
  • 命令关键字:startapp
mysite/
manage.py #
mysite/ # 包名
__init__.py # 作为 Python 包的标记
settings.py
urls.py # 相当于 Spring 的 Controller
asgi.py
wsgi.py
polls/ # 应用目录
migrations/ # 存放「迁移」文件
urls.py
apps.py
# apps.py
from django.apps import AppConfig


class PollsConfig(AppConfig):
name = 'polls' # Python 包名

视图层

# views.py
from django.http import HttpResponse


def index(request):
return HttpResponse("Hello, world. You're at the polls index.")

Django 3.1

# polls/urls.py
from django.urls import path

from . import views

urlpatterns = [
path('', views.index, name='index'), # '' 对应 polls/
]
# mysite/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
  • Django 3.1 path() 第一个参数为 route

Django 1.11 新增 urls.py,path 格式略微不同

# polls/urls.py
from django.conf.urls import url

from . import views

urlpatterns = [
url(r'^$', views.index, name='index'), # ^ 表示行的开头,$ 表示行的结束
]
# mysite/urls.py
from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
  • Django 1.11 path() 第一个参数为 regex

启动:

$ python3 manage.py runsever
$ python manage.py runsever

测试:

http://localhost:8000/polls/  # polls/ 对应 polls.urls
http://localhost:8001/polls/ # polls/ 对应 polls.urls

模型层

在 Django 里写一个使用数据库的 Web 应用的第一步是定义模型,Django 遵循 DRY Principle(不要重复地造轮子 Don’t repeat yourself)

# models.py
from django.db import models

class Question(models.Model):
question_text = models.CharField(max_length=200) # char,最长长度为 200
pub_date = models.DateTimeField('date published') # date_time,默认值为 date published?

class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE) # 外键,Choice 关联 Question
choice_text = models.CharField(max_length=300) # char,最长长度为 200
votes = models.IntegerField(default=0)

一个 Model(模型)对应一个表,一个 Field 对应一个表字段

Question 为 django.db.models.Model 类的子类,question_text 为 Field 的子类

在 settings.py 中配置我们添加的 polls App

# settings.py
INSTALLED_APPS = [
'polls.apps.PollsConfig', # PollsConfig 类写在文件 polls/apps.py 中
'django.contrib.admin',
...
]

执行 makemigrations 命令,将根据 models.py 生成一个对数据库修改的记录,称为「迁移」,修改 models.py 后,多次执行,将生成多个「迁移」

$ python3 manage.py makemigrations polls
$ python manage.py makemigrations polls
mysite/
manage.py #
mysite/ # 包名
...
polls/
migrations/
0001_initial.py
0002_auto_20201116_1316.py
# 0001_initial.py
class Migration(migrations.Migration):
...

可通过 sqlmigrate 命令查看「迁移」对应的 SQL

$ python3 manage.py sqlmigrate polls 0001
$ python manage.py sqlmigrate polls 0001

执行迁移文件,相当于执行对应 sql,将更新数据库

$ python3 manage.py migrate
$ python manage.py migrate

Admin

Admin 为 Django 自带应用,默认在启动时也将启动

# settings.py
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
...
]
# mysite/urls.py
urlpatterns = [
...
path('admin/', admin.site.urls),
]

创建管理员账号:

$ python3 manage.py createsuperuser
$ python manage.py createsuperuser

在 admin 中显示模型,用于图形化管理模型

# admin.py
from django.contrib import admin

# Register your models here.
from .models import Question

admin.site.register(Question)
  • 不用重启

在视图层使用模型

# views.py

from django.http import HttpResponse
from .models import Question


def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)

http://localhost:8000/polls/,浏览器输出

What's up

API / Shell

进入 shell

$ python3 manage.py shell
$ python manage.py shell

shell 命令:查、增、改

>>> from polls.models import Choice, Question
>>> Question.objects.all() # 显示 Question 所有数据
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save() # 插入一条数据
>>> q.id
>>> q.question_text
>>> q.pub_date
>>> q.question_text = "What's up?" # 修改字段
>>> q.save()
>>> Question.objects.all()

为模型添加自定义方法

# models.py
class Question(models.Model):
...
def __str__(self):
return self.question_text

def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1) # 时间小于一天


class Choice(models.Model):
...
def __str__(self):
return self.choice_text

使用自定义方法,shell 命令:查、增、外键

>>> from polls.models import Choice, Question
>>> Question.objects.all()
>>> Question.objects.filter(id=1) # 根据 id 过滤
>>> Question.objects.filter(question_text__startswith='What') # question_text 匹配开始字符
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year) # 匹配年限
>>> Question.objects.get(id=2) # DoesNotExist
>>> Question.objects.get(pk=1) # primary-key 为 1
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently() # 间隔年限小于 1 年,True
>>> q.choice_set.all() # 跟 q 相关的 Choice 集合
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
>>> c.question
<Question: What's up?> # 3 个 choice 都关联 question
>>> Choice.objects.all()
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]> # 关联 q 的有 3 个 choice
>>> q.choice_set.count()
3
Depp Wang wechat
个人公众号