路飞学城搭建值前后端结合

一.首页搭建

  1.轮播图

    admin站点配置支持图片上传

pip install Pillow     (这是在后端操作的,在之前搭建的后端环境中直接安装这个模块)

    默认情况下,Django会将上传的图片保存在本地服务器上,需要配置保存的路径。

我们可以将上传的文件保存在静态文件statics目录中,添加如下上传保存目录信息

配置代码 

# 访问静态文件的url地址前缀
STATIC_URL = '/static/'
# 项目中存储上传文件的根目录[暂时配置],注意,static目录需要手动创建否则上传文件时报错
MEDIA_ROOT=os.path.join(BASE_DIR,"luffy/static")

# 设置django的静态文件目录
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"luffy/static")
]

  把Home子应用注册到settings的INSTALLED_APPS中,并在models.py里面创建模型。

INSTALLED_APPS = [
    ...
    'home',
]

 

  home的views.py

    使用图片字段ImageFiled,字段选项使用upload_to可以设置保存图片的子目录,数据模型代码:

class bannerInfo(models.Model):
    """
    轮播图
    """
    # upload_to 存储子目录,真实存放地址会使用配置中的MADIE_ROOT+upload_to
    image = models.ImageField(upload_to='banner', verbose_name='轮播图', null=True)
    name = models.CharField(max_length=150, verbose_name='轮播图名称')
    link = models.CharField(max_length=150, verbose_name='轮播图广告地址')
    orders = models.IntegerField(verbose_name='显示顺序')
    is_show=models.BooleanField(verbose_name="是否上架",default=False)
    is_delete=models.BooleanField(verbose_name="逻辑删除",default=False)

    class Meta:
        db_table = 'ly_banner'
        verbose_name = '轮播图'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

  模型数据迁移:

python manage.py makemigrations
python manage.py migrate

  在xadmin站点添加轮播图数据

  通过如下命令安装xadmin的最新版

pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2

  在配置文件中注册如下应用:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'xadmin',
    'crispy_forms',
    'reversion',
    ...
]

# 修改使用中文界面
LANGUAGE_CODE = 'zh-Hans'

# 修改时区
TIME_ZONE = 'Asia/Shanghai'

    xadmin有建立自己的数据库模型类,需要进行数据库迁移

python manage.py makemigrations
python manage.py migrate

  

  在总路由中添加xadmin的路由信息

import xadmin
xadmin.autodiscover()
​
# version模块自动注册需要版本控制的 Model
from xadmin.plugins import xversion
xversion.register_models()
​
urlpatterns = [
    path(r'xadmin/', xadmin.site.urls)
]

  创建超级用户

python manage.py createsuperuser

创建轮播图的模型管理类

luffy/home/adminx.py
import xadmin
from xadmin import views

class BaseSetting(object):
    """xadmin的基本配置"""
    enable_themes = True  # 开启主题切换功能
    use_bootswatch = True

xadmin.site.register(views.BaseAdminView, BaseSetting)

class GlobalSettings(object):
    """xadmin的全局配置"""
    site_title = "路飞学城"  # 设置站点标题
    site_footer = "路飞学城有限公司"  # 设置站点的页脚
    menu_style = "accordion"  # 设置菜单折叠

xadmin.site.register(views.CommAdminView, GlobalSettings)


# 轮播图
from .models import bannerInfo
class BannerInfoModelAdmin(object):
    list_display=["name","orders","is_show"]
xadmin.site.register(bannerInfo, BannerInfoModelAdmin)

  视图:

  luffy/home/views.py

from django.shortcuts import render

# Create your views here.

from django.db.models import Q
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import bannerInfo
class BannerInfoAPIView(APIView):
    """
    轮播图列表
    """
    def get(self,request):
        # 获取数据
        banners = bannerInfo.objects.filter(Q(is_show=True) & Q(is_delete=False)).order_by("-orders")
        # 调整banners的images字段

        # 序列化
        data = []
        for item in banners:
            data.append({
              # 拼接图片的url地址
              "image": "/static/" + item.image.url,
              "link":item.link,
              "orders":item.orders,
            })
        return Response(data)

  路由代码:

    子应用路由:luffy/home/urls.py

from django.urls import path,re_path
from . import views
urlpatterns = [
    path(r"banner/",views.BannerInfoAPIView.as_view()),
]

    

  总路由:

urlpatterns = [
    ...
    path('home/', include("home.urls")),
    # include 的值必须是 模块名.urls 格式,字符串中间只能出现一个圆点
]

 

  2.前端代码(去admin那边获取api数据的)

<template>
  <div class="banner">
      <el-carousel trigger="click" height="506px">
      <el-carousel-item v-for="item in banner_list">
        <a :href="item.link"><img :src="item.image"></a>
      </el-carousel-item>
    </el-carousel>
  </div>
</template>

<script>
  export default {
    name:"Banner",
    data(){
      return {
        banner_list:[],
      };
    },
    created: function(){
      // 获取轮播图
      this.$axios.get("http://api.luffycity.cn:8000/home/banner/").then(res => {
        this.banner_list = res.data
      }).catch(error => {
        console.log(error);
      });
    }
  }
</script>

<style scoped>
.banner img{
  width: 100%;
}
</style>

  3.前端去后端拿数据会涉及到跨域CORS的问题(前后端都需要设置)

    1.后端

      我们现在为前端和后端分别设置两个不同的域名

      window 系统: C:\Windows\System32\drivers\etc\host

      linux/mac系统: /etc/hosts

位置域名
前端 www.luffycity.cn
后端 api.luffycity.cn

 

  

    编辑/etc/hosts文件,可以设置本地域名

    在文件中增加两条信息

127.0.0.1   api.luffycity.cn
127.0.0.1   www.luffycity.cn

  通过浏览器访问drf项目,会出现以下错误信息

  

  可以通过settings的ALLOWED_HOSTS,设置允许访问

# 设置哪些客户端可以通过地址访问到后端
ALLOWED_HOSTS = [
    'api.luffycity.cn',
    'www.luffycity.cn',
    'localhost',  # 实际开发的时候不会写上localhost和127.0.0.1的
    '127.0.0.1',
]

    现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持。

    否则前端无法使用axios无法请求后端提供的api数据

    我们使用CORS来解决后端对跨域访问的支持。

    使用django-cors-headers扩展

在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'})

  安装

pip install django-cors-headers

 

  添加应用

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

 

  中间层设置【必须写在第一个位置】

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

 

  添加白名单

# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    '127.0.0.1:8080',
    'localhost:8080',
    'www.luffycity.cn:8080'
)
CORS_ALLOW_CREDENTIALS = True  # 允许ajax跨域请求时携带cookie

  完成了上面的步骤,我们就可以通过后端提供数据给前端使用ajax访问了。

 

   2.前端的配置

    安装

npm install  axios -S

   导入

    在main.js导入

// 导入axios
import axios from 'axios'; // 从node_modules目录中导入包
// 设置vue的全局子对象
Vue.prototype.$axios = axios; // 把对象挂载vue中


 

 

 

2. 显示登陆页面

  前端引入登陆页面的组件代码并补充路由地址

  Login.vue,代码:

  

<template>
  <div class="login box">
        <img src="https://www.luffycity.com/static/img/Loginbg.3377d0c.jpg" alt="">
        <div class="login">
            <div class="login-title">
                <img src="https://www.luffycity.com/static/img/Logotitle.1ba5466.png" alt="">
                <p>帮助有志向的年轻人通过努力学习获得体面的工作和生活!</p>
            </div>
            <div class="login_box">
                <div class="title">
                    <span @click="login_type=1" :class="login_type==1?'current':''">密码登录</span>
                    <span @click="login_type=2" :class="login_type==2?'current':''">短信登录</span>
                </div>
                <div class="inp" :class="login_type==1?'show':''">
                    <input v-model = 'username' type="text"  placeholder="用户名 / 手机号码" class="user">
                    <input v-model = 'password' type="password" name="" class="pwd" placeholder="密码">
                    <div id="geetest1" title="验证码"></div>
                    <div class="rember">
                        <p>
                            <input type="checkbox" class="no" name="a"></input>
                            <span>记住密码</span>
                        </p>
                        <p>忘记密码</p>
                    </div>
                    <button class="login_btn">登录</button>
                    <p class="go_login" >没有账号 <span>立即注册</span></p>
                </div>
        <div class="inp" :class="login_type==2?'show':''">
                    <input v-model = 'username' type="text"  placeholder="手机号码" class="user">
                    <input v-model = 'password' type="password" name="" class="pwd" placeholder="短信验证码">
          <div class="rember">
                        <p>
                            <input type="checkbox" class="no" name="a"></input>
                            <span>记住密码</span>
                        </p>
                        <p>忘记密码</p>
                    </div>
                    <button class="login_btn">登录</button>
                    <p class="go_login" >没有账号 <span>立即注册</span></p>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
  export default{
    name:"Login",
    data(){
      return {
          login_type:2,
          username:"",
          password:"",
      }
    },
    components:{

    }
  }
</script>

<style scoped>
.box{
    width: 100%;
    position: relative;

}
.box img{
    width: 100%;
}
.box .login {
    position: absolute;
    width: 500px;
    height: 400px;
    top: 50%;
    left: 50%;
    margin-left: -250px;
    margin-top: -300px;
}
.login .login-title{
     width: 100%;
    text-align: center;
}
.login-title img{
    width: 190px;
    height: auto;
}
.login-title p{
    font-family: PingFangSC-Regular;
    font-size: 18px;
    color: #fff;
    letter-spacing: .29px;
    padding-top: 10px;
    padding-bottom: 50px;
}
.login_box{
    width: 400px;
    height: auto;
    background: #fff;
    box-shadow: 0 2px 4px 0 rgba(0,0,0,.5);
    border-radius: 4px;
    margin: 0 auto;
    padding-bottom: 40px;
}
.login_box .title{
    font-size: 20px;
    color: #9b9b9b;
    letter-spacing: .32px;
    border-bottom: 1px solid #e6e6e6;
     display: flex;
        justify-content: space-around;
        padding: 50px 60px 0 60px;
        margin-bottom: 20px;
        cursor: pointer;
}
.login_box .title .current{
        color: #4a4a4a;
        border-bottom: 2px solid #84cc39;
}

.inp{
    width: 350px;
    margin: 0 auto;
  display: none;
}
.show{
  display: block;
}
.inp input{
    border: 0;
    outline: 0;
    width: 100%;
    height: 45px;
    border-radius: 4px;
    border: 1px solid #d9d9d9;
    text-indent: 20px;
    font-size: 14px;
    background: #fff !important;
}
.inp input.user{
    margin-bottom: 16px;
}
.inp .rember{
     display: flex;
    justify-content: space-between;
    align-items: center;
    position: relative;
    margin-top: 10px;
}
.inp .rember p:first-of-type{
    font-size: 12px;
    color: #4a4a4a;
    letter-spacing: .19px;
    margin-left: 22px;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    /*position: relative;*/
}
.inp .rember p:nth-of-type(2){
    font-size: 14px;
    color: #9b9b9b;
    letter-spacing: .19px;
    cursor: pointer;
}

.inp .rember input{
    outline: 0;
    width: 30px;
    height: 45px;
    border-radius: 4px;
    border: 1px solid #d9d9d9;
    text-indent: 20px;
    font-size: 14px;
    background: #fff !important;
}

.inp .rember p span{
    display: inline-block;
  font-size: 12px;
  width: 100px;
  /*position: absolute;*/
/*left: 20px;*/

}
#geetest{
    margin-top: 20px;
}
.login_btn{
     width: 100%;
    height: 45px;
    background: #84cc39;
    border-radius: 5px;
    font-size: 16px;
    color: #fff;
    letter-spacing: .26px;
    margin-top: 30px;
}
.inp .go_login{
    text-align: center;
    font-size: 14px;
    color: #9b9b9b;
    letter-spacing: .26px;
    padding-top: 20px;
}
.inp .go_login span{
    color: #84cc39;
    cursor: pointer;
}
</style>
View Code

   在routes/index.js中,添加路由

import Vue from "vue"
import Router from "vue-router"

// 导入需要注册路由的组件
import Home from "../components/Home"
import Login from "../components/Login"
Vue.use(Router);

// 配置路由列表
export default new Router({
  mode:"history",
  routes:[
    // 路由列表
    {
      name:"Home",
      path: "/home",
      component:Home,
    },
    {
      name:"Home",
      path: "/",
      component:Home,
    },
    {
      name:"Login",
      path: "/login",
      component:Login,
    }
  ]
})

 

 

 

posted @ 2019-03-26 09:47  阿布_alone  阅读(342)  评论(0编辑  收藏  举报
TOP