django笔记

概述

官网很多相关文档,省略。。。

一些文档是整理的网上资源,可以参考Yuan先生 的技术博客。

环境

  • python: 3.6
  • pip: 9.0.1
  • django: 1.11.7

安装Django

  • 根据自己环境安装pip
  • pip install Django

新建django工程

  • 创建Django工程(根据自己环境配置修改)
c:\Python36\Scripts\django-admin.exe startproject mysite

mysite:django工程名称

  • cd mysite目录下
python manage.py startapp blog

blog:应用名称

启动

python manage.py runserver 8090

目录结构

mysite目录

  • manage.py #入口文件
  • mysite
    • __init__.py #初始化文件
    • settings.py #项目主配置文件
    • urls.py #路由分配配置文件
    • wsgi.py #Django web server(封装socket,解析APP)

blog目录

  • __init__.py
  • admin.py
  • apps.py
  • models.py #数据库相关配置(orm)
  • tests.py #检测、测试
  • views.py #视图函数

settings.py文件配置

定义templates位置

修改TEMPLATES中的DIRS:

'DIRS': [os.path.join(BASE_DIR, 'templates')],

最后效果为

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',
            ],
        },
    },
]

创建APP后要在 INSTALLED_APPS 添加相应名称

比如,我这里创建的是blog应用

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]

添加mysql数据库连接

DATABASES 中修改

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'DBNAME',
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': 'db_host',
        'PORT': 'port',
    }
}

注释掉错误警告

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

指定静态文件位置(如:js、css、jpg等)

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'statics')
)

开启配置之旅

第一个页面

blog APP下views.py文件添加一个展示数据的函数

from django.shortcuts import render, HttpResponse

# Create your views here.


def cur_time(request):
    return HttpResponse('hello world!')
  • request: 请求,参数可以自定义,但必须有
  • HttpResponse: 返回(当请求成功后要返回的信息)

mysite下的urls.py添加相关路由信息

from blog import views    #导入blog下的views模块


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^cur_time', views.cur_time),
]

运行启动命令

python manage.py runserver 8090

浏览器打开 localhost:8090/cur_time 就能看到 hello world!信息了。

添加html文件

之前在 settings.py 配置文件中指定了html文件的路径。所以,django会在 templates 目录下获取html文件,在mysite工程下新建一个 templates 目录,最后整个工程目录机构为:

mysite

  • +mysite
  • +blog
  • +templates

在templates目录下新键一个cur_time.html的html文件并进行编辑,最后代码为

cat views.py

from django.shortcuts import render, HttpResponse

# Create your views here.
import datetime

def cur_time(request):
    times = datetime.datetime.now()
    return render(request, 'cur_time.html', {'abc': times})

cat cur_time.html

<!DOCTYPE html>
<html lang="en">
<body>
当前时间:
</body>
</html>

解释

  • render: 模版渲染,第一个是请求参数<request>,第二个参数是跳转的url名称,第三个是传递变量 abc
  • cur_time.html中的{{}}是jinja2的模版语言,abc 则是render传过来的变量名,注意两边有空格

再次访问浏览器,应该就能看到当前时间了。

HttpResponse与render的区别

  • HttpResponse:
    • 一个类,后面跟一个字符串,是实例化的一个对象,直接返回给客户端浏览器,django所有返回给客户端浏览器都是通过这个类实现的
  • render
    • 渲染工作,首先指定一个html文件,解析完成后调用HttpResponse类返回给客户端浏览器,html文件中的变量、{}都不会显示在客户端浏览器上

数据库连接

做一个userInfo信息表单,当用户填入相关信息提交后,数据存入数据库中,并展示信息功能

如前面settings.py中的配置文件指定的数据库

userInfo信息有三个字段:username、sex、email,所以需要在blog中的models.py进行初始化数据库操作

from django.db import models

# Create your models here.

class UserInfo(models.Model):
    username = models.CharField(max_length=64)
    sex = models.CharField(max_length=64)
    email = models.CharField(max_length=64)

运行初始化数据命令

python manage.py makemigrations

如果报类似如下错误

  File "C:\Python36\lib\site-packages\django\db\__init__.py", line 33, in __getattr__
    return getattr(connections[DEFAULT_DB_ALIAS], item)
  File "C:\Python36\lib\site-packages\django\db\utils.py", line 211, in __getitem__
    backend = load_backend(db['ENGINE'])
  File "C:\Python36\lib\site-packages\django\db\utils.py", line 115, in load_backend
    return import_module('%s.base' % backend_name)
  File "C:\Python36\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "C:\Python36\lib\site-packages\django\db\backends\mysql\base.py", line 30, in 
    'Did you install mysqlclient or MySQL-python?' % e
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'.
Did you install mysqlclient or MySQL-python?

原因:python3不支持MySQLdb,需要在工程mysite下的init.py文件中添加如下内容

import pymysql
pymysql.install_as_MySQLdb()

切记

  1. settings.py里的INSTALLED_APPS添加应用名称,否则报错:

          File "C:\Python36\lib\site-packages\django\db\models\base.py", line 118, in __new__
     "INSTALLED_APPS." % (module, name)
    RuntimeError: Model class blog.models.UserInfo doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
     
  2. django不会创建数据库,所以要提前手动创建。

mysite下的urls.py添加路由指向

from django.conf.urls import url
from django.contrib import admin
from blog import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^cur_time', views.cur_time),
    url(r'^userInfo', views.userInfo),  #添加userInfo路由指向
]

views.py更新后的内容为:

from django.shortcuts import render, HttpResponse
from blog import models    #导入models模块,用于数据库操作
# Create your views here.
import datetime

def cur_time(request):
    times = datetime.datetime.now()
    # return HttpResponse('hello world!')
    return render(request, 'cur_time.html', {'abc': times})

def userInfo(req):
    if req.method == "POST":
        u = req.POST.get('username', None)
        s = req.POST.get('sex', None)
        e = req.POST.get('email', None)

        # user={'username':username,"sex": sex, "email": email}

        models.UserInfo.objects.create(  #插入数据
            username=u,
            sex=s,
            email=e
        )
    user_list = models.UserInfo.objects.all() #从数据库中获取所有数据
    return render(req, "index.html", {"user_list": user_list})

index.html文件内容

<!DOCTYPE html>
<html lang="en">
<body>
    <form action="/userInfo/" method="post">
        <p>姓名<input type="text" name="username"></p>
        <p>性别<input type="text" name="sex"></p>
        <p>邮箱<input type="text" name="email"></p>
        <p><input type="submit" value="submit"></p>
    </form>
    <table border="1px">
        <tr>
            <td>姓名</td>
            <td>性别</td>
            <td>邮箱</td>
        </tr>
        
    </table>
</body>
</html>

表单以 post 提交后跳转到 userInfo 页面。

Django URL(路由系统)

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

urlpatterns = [
    url(正则表达式, views视图函数,参数,别名),
]

参数:

  • 一个正则表达式字符串
  • 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  • 可选的要传递给视图函数的默认参数(字典形式)
  • 一个可选的name参数

示例

from django.conf.urls import url
from django.contrib import admin
from blog import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^cur_time', views.cur_time),
    url(r'^userInfo', views.userInfo),

    url(r'^articles/2003/$', views.special_case_2003),
    #url(r'^articles/[0-9]{4}/$', views.year_archive),
    url(r'^articles/([0-9]{4})/$', views.year_archive),  #no_named group
    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),

]
  • URL匹配规则是由上到下,比如url(r’^articles/2003/$’, views.special_case_2003)和url(r’^articles/([0-9]{4})/$’, views.year_archive) 这两条,都是匹配四个数字。如果URL是articles/2003,虽然也属于^articles/([0-9]{4}),但是会优先匹配url(r’^articles/2003/$’, views.special_case_2003)。
  • 正则表达式添加()后,指定的views的视图函数也要增加一个自定义的形参,如上面的url(r’^articles/([0-9]{4})/$’, views.year_archive),在views.year_archive中的year_archive视图函数定义时也要添加一个形参:
def year_archive(req,year):
    return HttpResponse(year)

浏览器访问时就会返回year值

多个(),year_archive要设定多个形参

正则分组(Named groups)

有时候URL传参需要指定值,这里就会用到Python正则表达式的?Ppattern

named groups

ret=re.search('(?P\d{3})/(?P\w{3})','weeew34ttt123/ooo')

print(ret.group())
print(ret.group('id'))
print(ret.group('name'))
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),
]

参数名称(name param)

urlpatterns = [
    url(r'^index',views.index,name='bieming'),
]
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')
<!DOCTYPE html>
<html lang="en">
<body>
    <form action="{% url 'bieming' %}" method="post">
         用户名:<input type="text" name="username">
         密码:<input type="password" name="password">
         <input type="submit" value="submit">
     </form>
</body>
</html>

导入其他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')),
]

Django Views(视图函数)

浏览器 –(Rquest)–> WebServer

浏览器 <–(Response)– WebServer

http请求中产生两个核心对象:

- http请求: HttpRequest对象
- http响应: HttpResponse对象
  1. HttpRequest对象的属性和方法:

     # path:       请求页面的全路径,不包括域名
     #
     # method:     请求中使用的HTTP方法的字符串表示。全大写表示。例如
     #
     #                    if  req.method=="GET":
     #
     #                              do_something()
     #
     #                    elseif req.method=="POST":
     #
     #                              do_something_else()
     #
     # GET:         包含所有HTTP GET参数的类字典对象
     #
     # POST:       包含所有HTTP POST参数的类字典对象
     #
     #              服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过
     #              HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用
     #              if req.POST来判断是否使用了HTTP POST 方法;应该使用  if req.method=="POST"
     #
     #
     #
     # COOKIES:     包含所有cookies的标准Python字典对象;keys和values都是字符串。
     #
     # FILES:      包含所有上传文件的类字典对象;FILES中的每一个Key都是标签中                     name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:
     #
     #             filename:      上传文件名,用字符串表示
     #             content_type:   上传文件的Content Type
     #             content:       上传文件的原始内容
     #
     #
     # user:       是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前
     #              没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你
     #              可以通过user的is_authenticated()方法来辨别用户是否登陆:
     #              if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
     #              时该属性才可用
     #
     # session:    唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。
    
     #方法
     get_full_path(),   比如:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123
     req.path:/index33
     

    注意一个常用方法:request.POST.getlist(‘’)

  2. HttpResponse对象:

    对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。

    HttpResponse类在django.http.HttpResponse

    在HttpResponse对象上扩展的常用方法:

     页面渲染:         render()(推荐)
    render_to_response(), 页面跳转: redirect("路径") locals(): 可以直接将函数中所有的变量传给模板

    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="duanruijun"
         return render(req,"my backend.html",locals())
     

    login.html

     <form action="/login/" method="post">
         <p>姓名<input type="text" name="username"></p>
         <p>性别<input type="text" name="sex"></p>
         <p>邮箱<input type="text" name="email"></p>
         <p><input type="submit" value="submit"></p>
     </form>
     

    my backend.html

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

模版

什么是模版语言

简单说就是html+逻辑控制语句。

模版常用用例 – 万能的句号点(.)

urls.py

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

from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),

views.py

from django.shortcuts import render
import datetime

# Create your views here.
def index(req):
    class profile(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    s1 = [1,22,333]
    s2 = {'username': 'duanrj', 'email': '123@qq.com'}
    s3 = datetime.datetime.now()
    s4 = profile("Bob", "20")
    s5 = 'hello'
    s6 = 6
    s7 = []
    s8 = "跳转"
    return render(req, 'index.html', {
        'value1': s1,
        'value2': s2,
        'value3': s3,
        'value4': s4,
        'value5': s5,
        'value6': s6,
        'value7': s7,
        'value8': s8,
    })

index.html

<!DOCTYPE html>
<html lang="en">
<body>

====打印列表第n个值====
{{ value1.2 }}
====打印dict的username值====
{{ value2.username }}
打印对象的属性
{{ value3.year }}
====打印对象的属性2====
{{ value4 }}
{{ value4.name }}
{{ value4.age }}
====模版语言中的遍历==== {% for i in obj %}

{{ forloop.counter }}:{{ i }}


//索引从1开始

{{ forloop.counter0 }}:{{ i }}


//索引从0开始 {% endfor %} ====filter:小写转为大写====
{{ value5 | upper }}
{{ value5 | lower }}
{{ value5 | capfirst }}
{{ value5 | first }}
====算数运算====
{{ value6 | add:5 }}
====为空时提示信息====
{{ value7 | default:'空的' }}
====当成普通字符串处理====
{{ value8 }}
如果想把类似于html 标签的都渲染出来可以这样
{% autoescape off %} {{ value8 }} {% endautoescape %} 也可以用safe {{ obj|safe }} ====禁止render==== {% verbatim %} {{ name }} {% endverbatim %} </body> </html>

filter

作用于简单操作,简化前后端开发重复性工作