python_fullstack—Django框架(二)-Django基础一

Django基础一

一、Django基本命令操作

1、下载&安装

# 建议安装最新LTS版
pip3 install django==1.11.11

2、创建项目

①创建一个名为mysite的Django项目

django-admin startproject mysite

②目录结构说明

mysite/
├── manage.py   # Django项目里面的工具,通过它可以调用django shell和数据库等。
└── mysite      # 项目目录
    ├── __init__.py
    ├── settings.py  # 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
    ├── urls.py  # 路由 --> 负责把URL模式映射到应用程序。
    └── wsgi.py  # runserver命令就使用wsgiref模块做简单的web server

3、创建应用

①在mysite项目下创建应用,例如app01:

python manage.py startapp app01

②目录结构

app01
├── __init__.py
├── admin.py
├── apps.py
├── migtations
    ├── __init__.py
├── models.py
├── tests.py
└── views.py

4、基本操作命令:

# 启动服务
python manage.py runserver 127.0.0.1:8000

# 同步更改数据库表或字段
python manage.py syncdb
注意:Django 1.7.1 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate

# 清空数据库
python manage.py flush

# 创建超级管理员
python manage.py createsuperuser
# 按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填
# 修改用户密码可以用:
python manage.py changepassword username

# Django 项目环境终端
python manage.py shell

# Django 项目环境终端
python manage.py dbshell

# 更多命令
python manage.py

5、static配置

STATIC文件还可以配置STATICFILES_DIRS,指定额外的静态文件存储位置。(STATIC_URL的含义与MEDIA_URL类似)

注意1:

#为了后端的更改不会影响前端的引入,避免造成前端大量修改

STATIC_URL = '/static/'               #引用名
STATICFILES_DIRS = (
    os.path.join(BASE_DIR,"statics")  #实际名 ,即实际文件夹的名字
)

#django对引用名和实际名进行映射,引用时,只能按照引用名来,不能按实际名去找
#
#------error-----不能直接用,必须用STATIC_URL = '/static/':
#

注意2(statics文件夹写在不同的app下,静态文件的调用):

STATIC_URL = '/static/'
STATICFILES_DIRS=(
    ('hello',os.path.join(BASE_DIR,"app01","statics")) ,
)
#

注意3:

STATIC_URL = '/static/'
 {% load staticfiles %}
# 

二、路由配置系统(URLconf)

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。

urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]
参数说明:
    一个正则表达式字符串
    一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
    可选的要传递给视图函数的默认参数(字典形式)
    一个可选的name参数

1、URLconf的正则字符串参数

简单配置

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

'''
NOTE:
1、一旦匹配成功则不再继续
2、若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
3、不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
4、每个正则表达式前面的'r' 是可选的但是建议加上。

一些请求的例子:

/articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。
/articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。
/articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数
                   views.month_archive(request, '2005', '03')。
'''

# 设置项是否开启URL访问地址后面不为/跳转至带有/的路径
APPEND_SLASH=True

有名分组(named group)

在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。在Python正则表达式中,命名正则表达式组的语法是(?P< name>pattern),其中name 是组的名称,pattern 是要匹配的模式。
下面是以上URLconf 使用命名组的重写:

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2})/$', views.article_detail),
]

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。例如:

/articles/2005/03/    
请求将调用views.month_archive(request, year='2005', month='03')函数
/articles/2003/03/03/ 
请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。

在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序。当然,这些好处是以简洁为代价;有些开发人员认为命名组语法丑陋而繁琐。

URLconf 在什么上查找

URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。
例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/,在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数。

捕获的参数永远是字符串

每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

url(r'^articles/(?P[0-9]{4})/$', views.year_archive),
views.year_archive() 的year 参数将是一个字符串

指定视图参数的默认值

有一个方便的小技巧是指定视图参数的默认值。 下面是一个URLconf 和视图的示例:

# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P[0-9]+)/$', views.page),
]
# View (in blog/views.py)
def page(request, num="1"):

在上面的例子中,两个URL模式指向同一个视图views.page —— 但是第一个模式不会从URL 中捕获任何值。如果第一个模式匹配,page() 函数将使用num参数的默认值”1”。如果第二个模式匹配,page() 将使用正则表达式捕获的num 值

Including other URLconfs

#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.
#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:
from django.conf.urls import include, url
urlpatterns = [
   url(r'^admin/', admin.site.urls),
   url(r'^blog/', include('blog.urls')),
]

2、传递额外的选项给视图函数(了解)

URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^blog/(?P[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year=’2005’, foo=’bar’)。这个技术在Syndication 框架中使用,来传递元数据和选项给视图。

3、name参数

urlpatterns = [
    url(r'^index',views.index,name='INDEX'),

]
###################

def index(req):
    if req.method=='POST':
        username=req.POST.get('username')
        password=req.POST.get('password')
        if username=='alex' and password=='123':
            return HttpResponse("登陆成功")

    return render(req,'index.html')

#####################


"en">

    "UTF-8">
    Title


{#     
#} "{% url 'INDEX' %}" method="post"> 用户名:"text" name="username"> 密码:"password" name="password"> "submit" value="submit">

三、编写视图

视图函数,简短来说叫做视图,是一个简单的Python函数,它接受web请求,并且返回web响应。

1、一个简单的视图

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "It is now %s." % now
    return HttpResponse(html)

'''
http请求-响应过程中有两个核心对象:
        http请求对象:HttpRequest
        http响应响应:HttpResponse
所在位置:django.http
'''

2、基础三件套

HttpResponse

内部传入一个字符串参数,返回给浏览器。

def index(request):
# 业务逻辑代码
return HttpResponse("OK")        

render

结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

# 参数:
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。
status:响应的状态码。默认为200

redirect

-----------------------------------url.py
url(r"login",   views.login),
url(r"yuan_back",   views.yuan_back),

-----------------------------------views.py
def login(req):
if req.method=="POST":
    if 1:
        # return redirect("/yuan_back/")
        name="yuanhao"

        return render(req,"my backend.html",locals())

return render(req,"login.html",locals())

def yuan_back(req):
name="Yang"
return render(req,"my backend.html",locals())

-----------------------------------login.html
"/login/" method="post">

姓名"text" name="username">

性别"text" name="sex">

邮箱"text" name="email">

"submit" value="submit">

-----------------------------------my_backend.html

用户{{ name }}你好

  • 总结: render和redirect的区别:
    • if render的页面需要模板语言渲染,需要的将数据库的数据加载到html,那么所有的这一部分除了写在yuan_back的视图函数中,必须还要写在login中,代码重复,没有解耦.
    • the most important: url没有跳转到/yuan_back/,而是还在/login/,所以当刷新后又得重新登录

四、Template

1、模板系统的介绍

  • 直接将HTML硬编码到你的视图里却并不是一个好主意。 让我们来看一下为什么:
    • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。
    • Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
    • 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。基于这些原因,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题。
    • python的模板:HTML代码+逻辑控制代码

2、模板支持的语法

  • 变量(使用双大括号来引用变量)
    语法格式:{{var_name}}
  • 深度变量的查找(万能的句点号)
    在到目前为止的例子中,我们通过 context 传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。
#最好是用几个例子来说明一下。
# 首先,句点可用于访问列表索引,例如:

>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
'Item 2 is carrots.'

#假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点:
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
'Sally is 43 years old.'

#同样,也可以通过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有
#year 、 month 和 day 几个属性,你同样可以在模板中使用句点来访问这些属性:

>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
1993
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
'The month is 5 and the year is 1993.'

# 这个例子使用了一个自定义的类,演示了通过实例变量加一点(dots)来访问它的属性,这个方法适
# 用于任意的对象。
>>> from django.template import Template, Context
>>> class Person(object):
...     def __init__(self, first_name, last_name):
...         self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
'Hello, John Smith.'

# 点语法也可以用来引用对象的方法。 例如,每个 Python 字符串都有 upper() 和 isdigit()
# 方法,你在模板中可以使用同样的句点语法来调用它们:
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
'123 -- 123 -- True'

# 注意这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的
# 方法。
  • 变量的过滤器(filter)的使用
    语法格式:{{obj|filter:param}}
方法 介绍
add 给变量加上相应的值
addslashes 给变量中的引号前加上斜线
capfirst 首字母大写
cut 从字符串中移除指定的字符
date 格式化日期字符串
default 如果值是False,就替换成设置的默认值,否则就是用本来的值
default_if_none 如果值是None,就替换成设置的默认值,否则就使用本来的值

- 标签(tag)的使用(使用大括号和百分比的组合来表示使用tag)
语法格式:{% tags %}

tag方法 介绍
{% if %} {% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容
{% for %} {% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
csrf_token 用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
{% url %} 引用路由配置的地址
{% with %} 用更简单的变量名替代复杂的变量名
{% verbatim %} 禁止render
{% load %}
  • 加载标签库:自定义filter和simple_tag

    • a、在app中创建templatetags模块(必须的)
    • b、创建任意 .py 文件,如:my_tags.py
    • c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}
    • d、使用simple_tag和filter(如何调用)
    • e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
  • 注意:

filter可以用在if等语句后,simple_tag不可以
{% if num|filter_multi:30 > 100 %}
    {{ num|filter_multi:30 }}
{% endif %}
  • extend模板继承
    本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。让我们通过修改 current_datetime.html 文件,为 current_datetime 创建一个更加完整的模板来体会一下这种做法:
    • 我们使用模板标签: {% block %} 。 所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。 每个{% block %}标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。
    • 在加载 current_datetime.html 模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。 模板引擎立即装载其父模板,即本例中的 base.html 。此时,模板引擎注意到 base.html 中的三个 {% block %} 标签,并用子模板的内容替换这些 block 。因此,引擎将会使用我们在 { block title %} 中定义的标题,对 {% block content %} 也是如此。 所以,网页标题一块将由{% block title %}替换,同样地,网页的内容一块将由 {% block content %}替换。

五、数据库与ORM

1、数据库的配置

  • django默认支持sqlite,mysql, oracle,postgresql数据库。
    • sqlite
      django默认使用sqlite的数据库,默认自带sqlite的数据库驱动,引擎名称:
      django.db.backends.sqlite3
    • mysql
      引擎名称:django.db.backends.mysql
  • mysql驱动程序
    • MySQLdb(mysql python)
    • mysqlclient
    • MySQL
    • PyMySQL(纯python的mysql驱动程序)
  • 在django的项目中会默认使用sqlite数据库,在settings里有如下设置:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'books',    #你的数据库名称
        'USER': 'root',   #你的数据库用户名
        'PASSWORD': '', #你的数据库密码
        'HOST': '', #你的数据库主机,留空默认为localhost
        'PORT': '3306', #你的数据库端口
    }
}
  • 注意
    NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建USER和PASSWORD分别是数据库的用户名和密码。设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。然后,启动项目,会报错:no module named MySQLdb
    这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL
    所以,我们只需要找到项目名文件下的__init__,在里面写入:
import pymysql
pymysql.install_as_MySQLdb()

2、ORM表模型

  • 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
  • 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。
  • 模型之间的三种关系:一对一,一对多,多对多。
    • 一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;
    • 一对多:就是主外键关系;(foreign key)
    • 多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)

3、ORM增删改查

  • ORM之增(create,save)
from app01.models import *
#create方式一:   Author.objects.create(name='Alvin')
#create方式二:   Author.objects.create(**{"name":"alex"})
#save方式一:     author=Author(name="alvin")
                        author.save()
#save方式二:     author=Author()
                        author.name="alvin"
                        author.save()
重点:创建存在一对多或多对多关系;处理外键关系的字段如一对多的publisher和多对多的authors
#一对多(ForeignKey):
    #方式一: 由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个
    #       字段设定对应值:
           Book.objects.create(title='php',
                               publisher_id=2,   #这里的2是指为该book对象绑定了Publisher表中id=2的行对象
                               publication_date='2017-7-7',
                               price=99)

    #方式二:
    #       <1> 先获取要绑定的Publisher对象:
        pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
                state_province='河北',country='China',website='http://www.hbu.com')
    OR  pub_obj=Publisher.objects.get(id=1)
    #       <2>将 publisher_id=2 改为  publisher=pub_obj

#多对多(ManyToManyField()):

    author1=Author.objects.get(id=1)
    author2=Author.objects.filter(name='alvin')[0]
    book=Book.objects.get(id=1)
    book.authors.add(author1,author2)
    #等同于:
    book.authors.add(*[author1,author2])
    book.authors.remove(*[author1,author2])
    #-------------------
    book=models.Book.objects.filter(id__gt=1)
    authors=models.Author.objects.filter(id=1)[0]
    authors.book_set.add(*book)
    authors.book_set.remove(*book)
    #-------------------
    book.authors.add(1)
    book.authors.remove(1)
    authors.book_set.add(1)
    authors.book_set.remove(1)

#注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式
#     如果第三张表是自己创建的:
     class Book2Author(models.Model):
            author=models.ForeignKey("Author")
            Book=  models.ForeignKey("Book")
#     那么就还有一种方式:
            author_obj=models.Author.objects.filter(id=2)[0]
            book_obj  =models.Book.objects.filter(id=3)[0]

            s=models.Book2Author.objects.create(author_id=1,Book_id=2)
            s.save()
            s=models.Book2Author(author=author_obj,Book_id=1)
            s.save()
  • ORM之删(delete)
>>> Book.objects.filter(id=1).delete()
(3, {'app01.Book_authors': 2, 'app01.Book': 1})
我们表面上删除了一条信息,实际却删除了三条,因为我们删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。
  • ORM之改(update和save)
  • ORM之查(filter,value)

六、Admin配置

你可能感兴趣的:(Django框架)