• 第十七章:Python の Web开发基础(四) MVC与Django


    本課主題

    • MVC 介绍
    • Django 介紹

    MVC 介绍

    controllers 处理用户请求

    views 放置HTML模版

    models 操作数据库

    MVC框架就是目录的归类

    MVC 是一种软件开发的方法,它把代码的定义和数据访问的方法(模型)与请求逻辑 (控制器)还有用户接口(视图)分开来

     

    Django 介紹

    Django开发的一般流程包括模型设计、URL设计、视图编码、模板设计,搭建Django应用的一种典型流程是:先设计好模型,然后就尽快把admin 运行起来,以便你的员工、客户可以尽快开始填充数据。之后,你再考虑该如何把数据呈现给用户

    创建 Django  

    1. 创建 project
      django-admin startproject mysite
      • 创建一个叫 mysite 的 project,会自动生成以下几个 py 文件:
      • setting.py #配置文件, 例如增加缓存功能,加密加盐
      • urls.py #路由系统,URL 保存了一个函数和网页的对应关系
      • wsgi.py #WSGI,封装了socket 对象和功能,它是一套规则、接口
      • manage.py #负责管理 Django 程序,比如创建 APP,运行 Django 程序和在数据库中创建表
    2. 创建虚拟环境,用来安装 django 
      virtualenv -p python3 venv
    3. 创建 App
      创建一个程序叫 app01,在这个文件夹下面有 migrations 文件夹和以下的 py 文件
      cd mysite
      python3 manage.py startapp app01

      生成的文件

      migrations/		# 数据修改表结构
      admin.py		# Django 为我们提供的后台管理
      apps.py			# 配置当前 App
      models.py		# ORM,写指定的类 通过命令创建数据库结构表
      tests.py		# 单元测试
      views.py		# 业务代码
    4. 运成 Django 程序
      python3 manage.py runserver 127.0.0.1:8000
    5. 注册 App
      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'app01', # 注册 APP
      ]
    6. 在 sqlite 中创建表
      python3 manage.py makemigrations
      python3 manage.py migrate
    7. xxxx

    URL设计

    在 URL 中写入相对的路径,下面例子加了一个 h.html 的 url 路径,你只须要访问时 http://127.0.0.1:8000/h.html/ 就可以看到 home 函数返回的 <h1>Welcome to GRILLFISH!</h1>, django 必须返回 HttpResponse 对象,在 URL 路由中有 Function Based View (FBV) 和 Class Based View (CBV) 之分,你可以在路由中输入视图函数 views.login 或者是类视图函数 views.Home.as_view( )

    from django.shortcuts import HttpResponse
    
    def home(request):
        return HttpResponse('<h1>Welcome to GRILLFISH!</h1>')
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('h.html/', home), #url 路径和函数对应关系
    ]

    URL 路由中正規表达式的用法

    用户可以在 urls 中以正規表达式来设计路由規则,好的路由设计是一个好网站的基本条件

    from django.urls import path, re_path
    from app01 import views
    urlpatterns = [
        path(r'index/', views.index),
        re_path(r'fakedindex/(?P<year>d+)/', views.index, name="index"),
        re_path(r'details/(d+)/', views.details), # 导入 re_path 来使用正規表达式
    ]
    

    定义好路由規则,然后定义 views.py

    # views.py
    def index(request):
    	USER_DICT = {
        1: {'username':'root1','email':'root1@live.com'},
        2: {'username':'root2','email':'root2@live.com'},
        3: {'username':'root3','email':'root3@live.com'},
        4: {'username':'root4','email':'root4@live.com'},
        5: {'username':'root5','email':'root5@live.com'},
    	}	
        return render(request, 'index.html',{'user_list': USER_DICT})
    

    和 html 的 render 方法

    <p>
        {% for k, v in user_list.items %}
            <li><a target="_blank" href="/details/{{k}}/"> {{v.username}} </a></li>
        {% endfor %}
    </p>

    不同正規表达式的路由定义对应的函数方法也有些不同,可以用以下几个方法生成 url,具体方法如下:

    url(r'^details-(d+)-(d+).html', views.details)
    # views.py
    def func(request, nid, uid):
        pass
    def func(request, *args):
        args = (2,9)
    def func(request, *args, **kwargs):
        args = (2,9)
    
    url(r'^details-(?P<nid>d+)-(?P<uid>d+).html', views.details)
    # views.py
    def func(request, nid, uid):
        pass
    def func(request, **kwargs):
        kwargs = {'nid': 2, 'uid': 9}
    def func(request, *args, **kwargs):
        args = (2,9)
    正規表达式和函数的定义

    URL 路由分发

    在 Django 中可以通过加入 include 来分发不同 app 中的 urls,然后进行处理,假如新增一个 app02 的子程序,然後在主程序的 urls.py 中加入以下路由关系,这样程序也照样可以正常连行

    from django.conf.urls import url, include
    urlpatterns = [
        url(r'cmdb/', include('app01.urls')),
        url(r'monitor/', include('app02.urls')),
    ]
    

    创建额外的文件夹

    创建 templates 文件夹来存放 HTML 文件,创建 static 文件夹来存放 CSS 文件和 JAVASCRIPT 文件 

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/common.css" /> <!--  从 /static/ 文件夹中找 common.css -->
    </head>
    <body>
        <form action="/login/" method="POST"> <!--  以POST的方式提交数据到 /login/ URL -->
            <p> <label for='username'>用戶名,</label>
                <input id='username' type='text' />
            </p>
            <p> <label for='passwd'>密碼,</label>
                <input id='passwd' type='password' />
                <input type='submit' value='提交'/>
            </p>
        </form>
        <script src="/static/jquery-1.12.4.js"></script> <!--  从 /static/ 文件夹中找 jquery -->
    </body>
    </html>
    templates 和 static 文件

    然后要在 setting.py 中定义 templates 和 staticfile directory, 这样就可以有在 views.py 中简单调用 render 函数来实现业务逻辑。 

    def login(request):
        # f = open('templates/login.html','r',encoding='utf-8')
        # data = f.read()
        # f.close()
        # return HttpResponse(data)
        return render(request, 'login.html')
    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',
                ],
            },
        },
    ]
    templates 文件夹定义
    STATIC_URL = '/static/'
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'static'),
    )
    static 文件夹定义

    以 GET 的方式提交请求通常是用来获取数据,內容会在 URL中;以 POST 的方式提交请求時,内容会包含在 RequestBody 中;下面介紹的是 render 模板和 redirect 的作用。redirect 只接受 url 路径, 比如 www.baidu.com 或者是本地 url,/login/

    from django.shortcuts import render
    from django.shortcuts import redirect
    
    # Create your views here.
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('user',None)
            pwd = request.POST.get('pwd',None)
            if user == 'root' and pwd == '123':
                return redirect('http://google.com')
    
        return render(request, 'login.html')
    render 和 redirect

    文件上传的处理需要

    file_obj = request.FILES.get('f1',None)
    
    import os
    file_path = os.path.join('uploads', file_obj.name)
    with open(file_path, mode='wb') as f:
        for i in file_obj.chunks():
            f.write(i)

    可以在 views.py 中创建类来封装 get 和 post 方法,

    from django.views import View
    class Home(View):
    
        def get(self, request):
            print(request.method)
            return render(request, 'home.html')
    
        def post(self, request):
            print(request.method, 'POST')
            return render(request, 'home.html')
    

    在 url.py 中加入以下语句就可以调用上述的类

    path(r'home/', views.Home.as_view()),
    

      

    class View:
        """
        Intentionally simple parent class for all views. Only implements
        dispatch-by-method and simple sanity checking.
        """
    
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
        def __init__(self, **kwargs):
            """
            Constructor. Called in the URLconf; can contain helpful extra
            keyword arguments, and other things.
            """
            # Go through keyword arguments, and either save their values to our
            # instance, or raise an error.
            for key, value in kwargs.items():
                setattr(self, key, value)
    
        @classonlymethod
        def as_view(cls, **initkwargs):
            """Main entry point for a request-response process."""
            for key in initkwargs:
                if key in cls.http_method_names:
                    raise TypeError("You tried to pass in the %s method name as a "
                                    "keyword argument to %s(). Don't do that."
                                    % (key, cls.__name__))
                if not hasattr(cls, key):
                    raise TypeError("%s() received an invalid keyword %r. as_view "
                                    "only accepts arguments that are already "
                                    "attributes of the class." % (cls.__name__, key))
    
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view
    
        def dispatch(self, request, *args, **kwargs):
            # Try to dispatch to the right method; if a method doesn't exist,
            # defer to the error handler. Also defer to the error handler if the
            # request method isn't on the approved list.
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            return handler(request, *args, **kwargs)
    
        def http_method_not_allowed(self, request, *args, **kwargs):
            logger.warning(
                'Method Not Allowed (%s): %s', request.method, request.path,
                extra={'status_code': 405, 'request': request}
            )
            return HttpResponseNotAllowed(self._allowed_methods())
    
        def options(self, request, *args, **kwargs):
            """Handle responding to requests for the OPTIONS HTTP verb."""
            response = HttpResponse()
            response['Allow'] = ', '.join(self._allowed_methods())
            response['Content-Length'] = '0'
            return response
    
        def _allowed_methods(self):
            return [m.upper() for m in self.http_method_names if hasattr(self, m)]
    class View 源码

     

    路由系统介绍

    Djgano 的生命周期是这样的:当有新的客户端请求来的时候,会向 urls.py 查找对应的函数,路由系统进行路由匹配,然后再跟据路由系统中找到视图函数 views.py,函数会从数据库获取数据,然后再以结合 HTML 实现数据。

    1. 普通关系
    2. 动态关系
    3. 路由关系

    模型设计

     

    request.method
    request.POST.get('nid', None)
    request.GET.get('nid', None) #lcoalhost/home?nid=123
    HttpResponse("Hello World!")
    render(request, 'login.html', {'error_msg': error_msg})
    redirect('http://google.com')
    request 方法

    复习题

    1. 如何创建一个 django 工程?
    2. 创建 django 工程后会有那些自动生成的文件夹,每个文件夹的功能是什么?
    3. Django 的生命週期是什么?
    4. 什么是 FBV 和 CBV ?

    作业

    1. 登录
    2. 主机管理页面,查看所有主机的信息
    3. 增加主机信息
    4. 查看详细

    參考資料 

    银角大王:Python之路【第十六篇】:Django【基础篇】

    金角大王:

    其他:

  • 相关阅读:
    Linux内核分析
    socket的protocal参数
    linux修改系统时间
    asdfadsf
    NoSQL数据库笔谈
    scrapy安装
    数字证书及CA的扫盲介绍
    Java数据类型
    EXISTS的用法
    python链接
  • 原文地址:https://www.cnblogs.com/jcchoiling/p/6240842.html
Copyright © 2020-2023  润新知