zoukankan      html  css  js  c++  java
  • 测试同学动手搭个简易web开发项目

    技术栈

    node.js, vue.js, axios, python, django, orm, restful api, djangorestframework, mysql, nginx, jenkins.

    环境配置

    操作系统

    Windows 7 旗舰版,Service Pack 1。

    前端

    Node.js

    >node -v
    v12.18.0
    >npm -v
    6.14.4
    

    Vue.js

    >vue -V(大写)
    @vue/cli 4.4.1
    

    后端

    Python

    >python --version
    Python 3.7.2
    

    Django

    >python -m django --version
    3.0.7
    

    数据库

    MySQL

    >mysqladmin --version
    mysqladmin  Ver 8.0.19 for Win64 on x86_64 (MySQL Community Server - GPL)
    

    命令行登录mysql,

    >mysql -u root -p
    Enter password: ******
    

    查询数据库,

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | new_schema         |
    | performance_schema |
    | sakila             |
    | sys                |
    | world              |
    +--------------------+
    7 rows in set (0.00 sec)
    

    代理

    Nginx

    在nginx安装目录执行start nginx,浏览器访问http://localhost:80,

    1592456182850

    持续集成

    Jenkins

    安装后,会自动打开http://localhost:8080/,

    1592979912495_副本

    软件安装过程就不赘述了,聪明的你一定知道怎么安。

    项目搭建

    本文的目的是走通整个项目的链路,于是会“弱化”掉系统功能的实现。

    创建后端工程

    执行django-admin startproject djangotest创建项目。

    cd djangotest,执行python manage.py startapp myapp创建应用。

    python manage.py runserver,启动服务,访问http://localhost:8000/,

    1591519905326_副本

    创建RESTful API

    安装mysqlclient和djangorestframework,

    pip --default-timeout=6000 install -i https://pypi.tuna.tsinghua.edu.cn/simple mysqlclient
    
    pip --default-timeout=6000 install -i https://pypi.tuna.tsinghua.edu.cn/simple djangorestframework
    

    在settings.py中,添加'rest_framework'和'myapp',

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

    同时修改数据库配置,

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '127.0.0.1',
            'PORT': 3306,
            'NAME': 'world',
            'USER': 'root',
            'PASSWORD': '123456'
        }
    }
    

    在myappmodels.py添加model,model叫做HellloDjango,有2个字段id和name,

    from django.db import models
    
    # Create your models here.
    
    
    class HelloDjango(models.Model):
        id = models.AutoField(primary_key=True)
        name = models.CharField(null=False, max_length=64, unique=True)
    

    执行python manage.py makemigrations,提交,

    >python manage.py makemigrations
    Migrations for 'myapp':
      myappmigrations001_initial.py
        - Create model HelloDjango
    

    执行python manage.py migrate,创建,

    >python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, myapp, sessions
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying admin.0003_logentry_add_action_flag_choices... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying auth.0009_alter_user_last_name_max_length... OK
      Applying auth.0010_alter_group_name_max_length... OK
      Applying auth.0011_update_proxy_permissions... OK
      Applying myapp.0001_initial... OK
      Applying sessions.0001_initial... OK
    

    看看数据库,新增了auth_和django_开头的表,以及model映射的表myapp_hellodjango,

    mysql> show tables;
    +----------------------------+
    | Tables_in_world            |
    +----------------------------+
    | auth_group                 |
    | auth_group_permissions     |
    | auth_permission            |
    | auth_user                  |
    | auth_user_groups           |
    | auth_user_user_permissions |
    | city                       |
    | country                    |
    | countrylanguage            |
    | django_admin_log           |
    | django_content_type        |
    | django_migrations          |
    | django_session             |
    | myapp_hellodjango          |
    +----------------------------+
    14 rows in set (0.00 sec)
    

    插入2条测试数据,

    mysql> insert into myapp_hellodjango(name) values('hello');
    Query OK, 1 row affected (0.09 sec)
    
    mysql> insert into myapp_hellodjango(name) values('django');
    Query OK, 1 row affected (0.20 sec)
    
    mysql> select * from myapp_hellodjango;
    +----+--------+
    | id | name   |
    +----+--------+
    |  2 | django |
    |  1 | hello  |
    +----+--------+
    2 rows in set (0.00 sec)
    

    照着官网的例子,在myapp目录下新增urls.py,添加rest代码,

    from django.conf.urls import url, include
    from rest_framework import routers, serializers, viewsets
    
    from .models import HelloDjango
    
    
    # Serializers define the API representation.
    class HelloSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = HelloDjango
            fields = ['id', 'name']
    
    
    # ViewSets define the view behavior.
    class HelloViewSet(viewsets.ModelViewSet):
        queryset = HelloDjango.objects.all()
        serializer_class = HelloSerializer
    
    
    # Routers provide an easy way of automatically determining the URL conf.
    router = routers.DefaultRouter()
    router.register(r'hello', HelloViewSet)
    
    urlpatterns = [
        url(r'demo/', include(router.urls)),
    ]
    
    

    在djangotest下的urls.py中添加路由,

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('myapp.urls'))
    ]
    

    通过这2个urls.py文件的指定,api接口的路径为,/api/demo/hello。

    执行python manage.py runserver启动服务,使用postman来调用http://127.0.0.1:8000/api/demo/hello/。先发1个post请求,往数据库新增1条数据,

    1592902408582_副本

    再发1个get请求,会看到返回了3条数据,2条预先插入的数据,1条post请求新增的数据,

    1592902449583_副本

    创建前端工程

    在djangotest根目录下,执行vue create vuetest,创建vue工程。

    默认安装,一路回车,啪啪啪。

    开始创建,

    Vue CLI v4.4.1
    a  Creating project in D:cicdvuetest.
    a  Initializing git repository...
    aa Installing CLI plugins. This might take a while...
    

    创建成功,

    a  Successfully created project vuetest.
    a  Get started with the following commands:
    
     $ cd vuetest
     $ npm run serve
    

    执行cd vuetestnpm run serve,前端工程就启动起来了,访问http://localhost:8080/,Welcome to Your Vue.js App,

    1591501593139_副本

    前端调后端接口

    此时djangotest的目录结构为,

    ├─djangotest
    │  ├─djangotest
    │  ├─myapp  # app
    │  ├─vuetest  # 前端
    │  ├─manage.py
    

    修改vuetestsrccomponentsHelloWorld.vue,添加{{info}},用来展示后端api返回的数据,

    <div class="hello">
      {{info}}
        <h1>{{ msg }}</h1>
    

    同时在<script>中使用axios添加ajax请求,请求http://127.0.0.1:8000/api/demo/hello/,将response.data赋值给info,

    <script>
    export default {
      name: 'HelloWorld',
      props: {
        msg: String
      },
      data() {
        return {
            info: 123
        }
      },
      mounted () {
        this.$axios
          .get('http://127.0.0.1:8000/api/demo/hello/')
          .then(response => (this.info = response.data))
          .catch(function (error) { // 请求失败处理
            console.log(error);
          });
      }
    }
    </script>
    

    为了运行起来,需要安装axios,

    npm install --save axios
    

    并在vuetestsrcmain.js中引入,

    import Vue from 'vue'
    import App from './App.vue'
    import axios from 'axios'
    
    Vue.config.productionTip = false
    
    Vue.prototype.$axios = axios;
    
    new Vue({
      render: h => h(App)
    }).$mount('#app')
    

    分别启动后端和前端服务,

    python manage.py runserver
    
    cd vuetest
    npm run serve
    

    嚯!ajax请求失败了,F12可以看到报错信息,

    localhost/:1 Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/demo/hello/' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    django的端口是8000,vue的端口是8080,vue在请求django的时候,出现了跨域问题。浏览器有个同源策略,域名+端口+协议都相同才认为是同一来源。

    通过配置django来解决,先安装django-cors-headers,

    pip install django-cors-headers
    

    在settings.py中添加中间件和开关,

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

    此时vue就可以请求到django提供的接口了,http://localhost:8080/

    1592972876066_副本

    前后端结合

    vuetest目录下创建vue.config.js,这是因为django只能识别static目录下的静态文件,这里指定vue生成静态文件时套一层static目录,

    module.exports = {
        assetsDir: 'static'
    };
    

    在vuetest目录下执行npm run build,生成静态文件到vuetest/dist文件夹。

    修改urls.py,指定django的模板视图,

    from django.conf.urls import url
    from django.contrib import admin
    from django.urls import path, include
    from django.views.generic import TemplateView
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('myapp.urls')),
        url(r'^$', TemplateView.as_view(template_name="index.html")),
    ]
    

    在settings.py中配置模板目录为dist文件夹,

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': ['vuetest/dist'],
            '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',
                ],
            },
        },
    ]
    

    指定静态文件目录为vuetest/dist/static,

    # Add for vuejs
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, "vuetest/dist/static"),
    ]
    

    浏览器访问http://localhost:8000/,显示的不再是django的欢迎页面,而是vue的页面。

    前后端结合完成。vue的8080可以停了。

    1592972876066_副本

    Nginx转发

    nginx常用3个命令,启动,重新加载,停止,

    nginx start
    nginx -s reload
    nginx -s stop
    

    修改conf ginx.conf,监听端口改为8090,添加转发proxy_pass http://localhost:8000;

       server {
            listen       8090;
            server_name  localhost;
    
            #charset koi8-r;
    
            #access_log  logs/host.access.log  main;
    
            location / {
                root   html;
                index  index.html index.htm;
                proxy_pass http://localhost:8000;
            }
    

    执行nginx start,浏览器访问http://localhost:8090/,也能正常访问djangotest。

    通过nginx将8090转发到了8000。

    持续集成

    本来想弄个pipline的,无奈家里这台破机器安装失败,windows也没有linux对jenkins支持好,只能将就做个鸡肋版本。

    New Item,命名为vuetest,添加vue的build脚本,

    d:
    cd D:cicddjangotestvuetest
    npm run build
    

    1592991544913_副本

    New Item,命名为djangotest,添加django的build脚本,

    d:
    cd D:cicddjangotest
    python manage.py runserver
    

    1592991578357_副本

    直接执行会报错python不是可运行命令。添加python环境变量,在首页左下角,

    1592983220698_副本

    把路径D:Python37添加为环境变量path并保存,

    1592983242033_副本

    建好的这2个job就可以用来编译vue和启动django了,

    1592991709156_副本

    专注测试,坚持原创,只做精品。欢迎关注公众号『东方er』
    版权申明:本文为博主原创文章,转载请保留原文链接及作者。

  • 相关阅读:
    Android笔记(六十六) android中的动画——XML文件定义属性动画
    Android笔记(六十五) android中的动画——属性动画(propertyanimation)
    python函数参数默认值及重要警告
    Python 列表
    Python数学运算入门把Python当作计算器
    Python 的非正式介绍
    python中为什么 if/while/def/class语句需要冒号?
    为什么Python在列表和元组的末尾允许使用逗号?
    现实世界中的 Python
    Python常见问题
  • 原文地址:https://www.cnblogs.com/df888/p/13191065.html
Copyright © 2011-2022 走看看