【Django】Django框架基础详述(一)

1、Django的介绍

Django是Python下的一款优秀的Web框架。
(1)什么是框架?
框架是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法。另一种定义认为,框架是可被应用开发者定制的应用骨架。
(2)Django的优点

  • 自带轮子众多,方便快速开发,如 Authentication,Cache,模板;
  • 天生的MVC设计模式;
  • 实用的管理后台;
  • 自带ORM,Template,Form,Authentication核心组件;
  • 简洁的URL设计;
  • 周边插件丰富。

(2)Django的缺点
Django的设计哲学:大量内置各种插件。Django比Flask、Tornado重量级。
Flask:轻量级,只设计引擎,其他都是作为周边插件,生态系统较完善,需要安装插件。
Tornado:用于多并发,异步场合,生态系统相对Django和Flask少,很多都需要自己实现。

2、Django的历史

最初开发者:Adrian 和 Simon。
开发背景: World Online维护几个新闻站点,要求快速发布新闻,快速建立其它新闻站点(快速开发,数据驱动)。
开源时间:2005年夏天 World Online小组宣布开源。
官方网站:https://www.djangoproject.com/
文档地址:https://docs.djangoproject.com/en/3.0/

3、Django的安装

使用版本: Django 3.0.2 和 Python3.7.3
Django安装

$ pip install django
$ python -c "import django; print(django.get_version())"

4、Django的组件

(1)示例需求:在web页面上,要求列出最新的10本书。
1)使用python CGI

#!/usr/bin/env python

import MySQLdb

print "Content-Type: text/html\n"
print "<html><head><title>Books</title></head>"
print "<body>"
print "<h1>Books</h1>"
print "<ul>"

connection = MySQLdb.connect(user='me', passwd='letmein', db='my_db')
cursor = connection.cursor()
cursor.execute("SELECT name FROM books ORDER BY pub_date DESC LIMIT 10")

for row in cursor.fetchall():
    print "<li>%s</li>" % row[0]

print "</ul>"
print "</body></html>"

connection.close()

2)使用Django

# models.py (the database tables)

from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=50)
    pub_date = models.DateField()


# views.py (the business logic)

from django.shortcuts import render
from models import Book

def latest_books(request):
    book_list = Book.objects.order_by('-pub_date')[:10]
    return render(request, 'latest_books.html', {'book_list': book_list})


# urls.py (the URL configuration)

from django.conf.urls import url
import views

urlpatterns = [
   url (r'^latest/$', views.latest_books),
]


# latest_books.html (the template)

<html><head><title>Books</title></head>
<body>
<h1>Books</h1>
<ul>
{% for book in book_list %}
<li>{{ book.name }}</li>
{% endfor %}
</ul>
</body></html>

(2)Django的基本组件
1)Model(models.py)
Model文件主要用一个 Python 类来描述数据表,我们 称之为 模型(model)。运用这个类,我们可以通过简单的 Python 的代码来创建、检索、更新、删除数据库中的记录而无需写一条又一条的SQL语句。
2)View(views.py)
View文件包含了页面的业务逻辑,称之为视图。 latest_books()函数叫做视图函数。
3)URL(urls.py)
该文件指出了什么样的 URL 调用什么视图。 在这个例子中 /latest/ URL 将会调用 latest_books() 这个函数。 换句话说,如果你的域名是example.com,任何人浏览网址http://example.com/latest/将会调用latest_books()这个函数。
4)Template(templates目录)
templates是 html 模板,它描述了这个页面的设计是如何的。 templates使用带基本逻辑声明的模板语言,如{% for book in book_list %}。
(3)基本响应流程

graph TD
    A[用户请求] --> B[urls.py]
    B --> C[views.py]
    C --> D[models.py]
    C --> E[templates]
    C --> A

5、Django的基本使用

(1)案例需求

  • 一个网站可以让用户投票,可以查看投票结果
  • 后台管理网站,可以添加删除修改投票

(2)新建项目

$ django-admin startproject project-name
$ django-admin startproject mysite

(3)运行项目

$ python manage.py runserver $bind_host:$listen_port

$ python manage.py runserver
$ python manage.py runserver 0.0.0.0:8000


(4)说明

  • 启动的是django内置webserver,仅用于开发测试。
  • 修改mysite/mysite/settings.py中的ALLOWED_HOSTS=[],将允许的主机或域名添加进来,可以允许访问该域名或主机的django的web页面。
  • 更改python文件后server会自动reload。

(5)目录结构

~/project $ tree mysite
mysite
├── manage.py			# Django管理工具
└── mysite
    ├── __init__.py
    ├── asgi.py
    ├── settings.py		# project的配置文件
    ├── urls.py
    └── wsgi.py

1 directory, 6 files

(6)实例一:hello world

# urls.py

from django.conf.urls import url
from django.contrib import admin
from django.http import HttpResponse

def index(request):
    return HttpResponse('This is index page.')
    
def hello(request):
    return HttpResponse('Hello world')
    
urlpatterns = [
    url(r'^$', index),
    url(r'^hello/$', hello)
]
  • urlpatterns:包含着URL实例的列表
  • url函数 (regex, view, **kwargs, name)
  • view接收function object,而不是执行函数,index和hello后不需要加()
  • urlpatterns中,路径前面的/不能加,后面的/必须加,当后面的/加上时,在浏览器中的地址最后的/可写可不写,不写时,会重定向到加/的地址,而urlpatterns如果后面的/不加,浏览器中最后的/不加的话正常访问,浏览器中加上/出现404页面
  • 项目入口urls:urls.py中的urlpatterns
  • request
  • HttpResponse

6、Django app

(1)Django app与Django project的区别
1)Django app是Django框架编写的应用,Django project是Django的配置文件。
2)Django app才能使用model。
3)Django app设计是可插拔的,新建的app可以在project目录中,也可以不在project目录中,通过项目目录中的settings文件中的INSTALLED_APPS=[]列表管理,新建的app必须写入该列表,app作为模块导入项目,模块路径必须在python path中。
(2)新建app

$ python manage.py startapp app-name
$ python manage.py startapp polls
$ django-admin startapp polls2

(3)目录结构

~/projects/mysite $ tree polls

polls
├── __init__.py
├── admin.py			# 管理后台设置
├── apps.py				# app的配置文件
├── migrations			# 数据迁移,将表结构更改写入数据库
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

(4)配置project settings导入app

# mysite/settings.py
...
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
...

(5)编写app view

# polls/views.py

from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, at polls index")

(6)编写urls

# mysite/urls.py

from django.conf.urls import url, include
...

urlpatterns = [
    url(r'^$', index),
    url(r'^hello/', hello),
    url(r'^polls/', include('polls.urls')),
    #url(r'admin', admin.site.urls),
]

# polls/urls.py (默认不存在)

from django.conf.urls import url
from . import views

urlpatterns = [
    url('^$', views.index, name='index')
]

7、Django数据库支持

(1)Django默认支持以下数据库:

  • sqlite
  • MySQL(MariaDB)
  • PostgreSQL
  • Oracle

(2)数据库设置

# mysite/settings.py
# 默认使用 sqlite
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# 使用 mysql
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db_name',
        'USER': 'user',
        'PASSWORD': 'password',
        'HOST': '127.0.0.1',
        'PORT': 3306,
    }
}

(3)Python 3.5 Mysql Driver
MySQLdb驱动不支持 Python3.5,可选驱动有:

  • pymysql:python写的,速度慢,使用方法见 https://my.oschina.net/waston/blog/544329
  • mysqlclient:fork的mysqldb,支持 python3.3+,速度快,django官方推荐
  • 在对db没有要求的情况下,postgre或许是个更好的选择,详见:https://docs.djangoproject.com/en/1.10/ref/databases/

8、编写 App models

(1)ORM介绍

  • 用python方法、数据结构访问db
  • 可以兼容不同数据库

(2)投票app的models编写

# polls/models.py

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

(3)field的类型及属性
field的类型:CharField,DateTimeField,IntegerField
field的属性:ForeignKey,on_delete,max_length,default,blank,null
(4)Models的迁移(Models Migrate)
1)应用场景
编写完数据模型需要应用到数据库,django为了能跟踪表结构的变化,增加了migrations版本控制功能,如果没有该功能每次表结构变化,就需要重新生成表结构,重新导入数据。
2)Models Migrate命令

$ ls polls/migrations
$ python manage.py makemigrations
Migrations for 'polls':
  0001_initial.py:
    - Create model Choice
    - Create model Question
    - Add field question to choice
$ ls polls/migrations
$ python manage.py sqlmigrate polls 0001_initial
$ python manage.py migrate							# 应用数据迁移到数据库
$ sqlite3 db.sqlite3								# 查看sqlite数据库
SQLite version 3.6.20
sqlite> .tables
django_migrations									# 存放元数据

$ python manage.py shell							# 进入ipython
>>> from django.utils import timezone
>>> from polls.models import Question, Choice
>>> q = Question(question_text=“What's new?”, pub_date=timezone.now())
>>> q.save()										# 保存到数据库中
>>> q.id; q.pk; q.question_text; q.pub_date;		# 访问属性

django中的时间有两种表示方式:

 from django.utils import timezone
 pub_date=timezone.now()					# 带时区的表示方式
 import datetime
 pub_date=datetime.datetime.now()			# 不带时区的本地时间表示方式

project的settings.py文件可以设置使用什么时区,其中I18N表示数据库中存的都是UTC时间,不同时区的用户请求再做转换。
(5)说明

  • 一个class代表一张表,多对多会产生额外一张关系表
  • 默认主键为id, 也可以自定义主键
  • 表名默认为 ${app_name}_${class_name_lower}

(6)models的增删改查
增加:

# 方式一:
q = Question(**kwargs)
q = Question(question_text='what is up?', pub_date=timezone.now())
q.save()
# 方式二:(objects管理器)
q = Question.objects.create(**kwargs)
q = Question.objects.create(question_text='what is wrong?', pub_date=timezone.now())

q.id
3
q.question_text
'what is wrong?'

查询:

Question.objects.all() 									# 查询表中所有数据,获取QuerySet,一个类list
Question.objects.filter(question_text="What's up?")		# 获取QuerySet,一个类list
Question.objects.filter(id_gt=1)						# 获取id大于1的object
Question.objects.get(id=1)								# 获取一个object,Question object

更改:

q = Question.objects.get(id=1)
q.question_text = 'some text'
q.save()

Question.objects.filter(id=1).update(question_text='Why ?')		# 返回int类型,表示更改了几条数据
1
Question.objects.filter(id_gt=1).update(question_text='What is it ?')
2

删除:

q = Question.objects.get(id=1)
q.delete()							# 返回删除了几条数据
(1, {'polls.Choice':0, 'polls.Question': 1})

Question.objects.filter(id=1).delete()
Question.objects.all().delete()

(7)给models增加一些方法

import datetime
from django.db import models
from django.utils import timezone

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    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):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

说明:

  • __str__ :返回的不是object,而是定义的text,方便调试,python3的方法。
  • __unicode__:返回的不是object,而是定义的text,方便调试,python2的方法。
  • timezone 带来的 datetime aware 和 naive问题:timezone是aware的,即带时区的,datetime是naive的,即不带时区的。

运行查看:

$ python manage.py shell
>>> from polls.models import Question, Choice
>>> from django.utils import timeozne
>>> q = Question.objects.create(question_text="How are you ?", pub_date=timezone.now())
>>> q = Question.objects.first()			# 没有上面create语句,需要执行该句。create不需要获取数据,可以直接得到
>>> q
<Question: How are you ?>
>>> q.was_published_recently()
>>> True
>>> d = timezone.now() - timezone.timedelta(days=2)
>>> q.pub_date = d
>>> q.save()								# create不用save,修改才需要save
>>> q.was_published_recently()
>>> False

(8)View中使用Model
需求:列出最近的5个问题。

# polls/views.py

from django.http import HttpResponse
from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]				# 倒序,支持切片
    latest_question_list = Question.objects.order_by('pub_date')[:5]				# 正序
    latest_question_list = Question.objects.all().order_by('-pub_date')[:5]			# 省略了all()函数调用
     latest_question_list = Question.objects.order_by('-pub_date').filter(id=5)		# 可以调用filter函数
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

(9)完成详情,提供投票,显示投票结果

# polls/views.py

def detail(request, question_id):
    return HttpResponse('Your are looking at question {}'.format(question_id))

def results(request, question_id):
    response = "You are looking at results of question {}".format(question_id)
    return HttpResponse(response)

def vote(request, question_id):
    return HttpResponse('Your are voting on question {}'.format(question_id))
    
    
# polls/urls.py

urlpatterns = [
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

说明:

  • (?P<question_id>[0-9]+):命名组捕获,获取一个key-value对,key为question_id,值为0-9的数字,相当于调用detail(request, question_id=123)。不用命名捕获相当于调用detail(request, 123)。
  • detail(request, question_id):调用方式。
  • args, kwargs always string:多个命名捕获就传入多个参数,即相当于调用:detail(request, **kwargs)。从URL中获取到的参数都是string类型,如果需要其他类型,需要做转换。
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页