Django 入门笔记

WSGI

WSGI:(Web Server Gateway Interface,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

原因:运行命令 django-admin startproject mysite 时,系统将去 /usr/local/bin 目录找可执行文件 django-admin,安装 Django 3.1 时,没有自动将可执行文件django-admin 软链(符号链接)/usr/local/bin,所以直接运行不好使,而使用 python3 -m django,m 含义module,将在 /Library/Frameworks/Python.framework/Versions/3.7 下的site-package 中查找

的 目录找此命令,找不到。安装 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)。Django 默认使用 SQLite 数据库。

# mysite/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# polls/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',
...
]

migrate「迁移」

执行 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
  • 数据保存在 db.sqlite3 这个文件中?
  • 项目启动后,将直接执行对 model 的修改。相当于执行 migrate,但不执行 makemigrations?重启项目不会自动执行 migrate 相关命令(修改了 comment 改为了 artical_comment,直接修改 comment 报错)
  • 使用 migrate 的好处是?
(ENV) [18:50:42] ~/workspace/demo-project git(master) ❱❱❱ python manage.py runserver
WARNING:root:[cy_settings] IS_FOR_TESTCASE=True, configcenter setup for testcase
WARNING:root:[cy_settings] IS_FOR_TESTCASE=True, configcenter setup for testcase
Performing system checks...

System check identified no issues (0 silenced).

You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

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
个人公众号