Vue+Django 旅游网项目 首页后端实现

轮播图

配置数据库

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

Vue+Django 旅游网项目 首页后端实现_ajax

创建应用

startapp system

创建数据库

Vue+Django 旅游网项目 首页后端实现_ide_02

编写模型

class Slider(models.Model):
name=models.CharField('名称',max_length=32)
desc=models.CharField('描述',max_length=100,null=True,blank=True)
types=models.SmallIntegerField('展现的位置',default=10)
img=models.ImageField('图片地址',max_length=255,upload_to='%Y%m/slider')
reorder=models.SmallIntegerField('排序字段',default=0,help_text="数字越大越靠前")
start_time=models.DateTimeField('生效开始时间',null=True,blank=True)
end_time=models.DateTimeField('生效结束时间',null=True,blank=True)
target_url=models.CharField('跳转的地址',max_length=255,null=True,blank=True)
is_valid=models.BooleanField('是否有效',default=True)
created_at=models.DateTimeField('创建时间',auto_now_add=True)
updated_at=models.DateTimeField('修改时间',auto_now=True)

class Meta:
db_table='system_slider'
ordering=['-reorder']

注册应用

Vue+Django 旅游网项目 首页后端实现_ide_03

同步数据库

makemigrations
migrate

Vue+Django 旅游网项目 首页后端实现_vue.js_04

Vue+Django 旅游网项目 首页后端实现_ajax_05

接口编写

from django.http import HttpResponse, JsonResponse
from django.shortcuts import render

# Create your views here.
from system.models import Slider


def slider_list(request):
""" 轮播图接口

"meta":[]
"objects":[]

"""
data ={
'meta':{},
'objects':[]
}
querset=Slider.objects.filter(is_valid=True)
for item in querset:
data['objects'].append({
'id':item.id,
'img_url': item.img.url,
'target_url':item.target_url,
'name': item.name
})
return JsonResponse(data)

utl设置

system/urls.py

from django.urls import path

from system import views

urlpatterns = [
path('slider/list', views.slider_list),
]

根urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
# 系统模块
path('system/',include('system.urls'))
]

测试

测试前需要在数据库中添加数据

Vue+Django 旅游网项目 首页后端实现_python_06

景点

新建应用

startapp sight 

注册

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

编写模型

class Sight(models.Model):
name = models.CharField('名称',max_length=64)
desc=models.CharField('描述',max_length=255)
main_img=models.ImageField('主图',upload_to='%Y%m/sight/',max_length=255)
banner_img=models.ImageField('详情主图',upload_to='%Y%m/sight/',max_length=255)
content=models.TextField('详情')
score=models.FloatField('评分',default=5)
min_price=models.FloatField('最低价格',default=0)
province=models.CharField('省份',max_length=32)
city=models.CharField('市区',max_length=32)
area=models.CharField('区/县',max_length=32,null=True)
town=models.CharField('乡镇',max_length=32,null=True)
is_top=models.BooleanField('是否为精选景点',default=False)
is_hot=models.BooleanField('是否为热门景点',default=False)
is_valid=models.BooleanField('是否有效',default=True)
created_at=models.DateTimeField('创建时间',auto_now_add=True)
updated_at=models.DateTimeField('修改时间',auto_now=True)
class Meta:
db_table:'sight'
ordering=['-updated_at']

数据库同步

makemigrations migrate 

Vue+Django 旅游网项目 首页后端实现_ajax_07

接口编写

根utls.py

urlpatterns = [
path('admin/', admin.site.urls),
# 系统模块
path('system/',include('system.urls')),
# 景点
path('sight/',include('sight.urls'))
]

sight urls.py

from django.urls import path

from sight import views

urlpatterns = [
# 景点列表接口
path('sight/list/', views.SightListView.as_view()),
]

views.py

from django.db.models import Q
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views.generic import ListView

from sight.models import Sight


class SightListView(ListView):
""" 景点列表 """
# 每页5条数据
paginate_by = 5

def get_queryset(self):
# 重写查询方法
query=Q(is_valid=True)
# 热门景点
is_hot = self.request.GET.get('is_hot',None)
if is_hot:
query=query & Q(is_hot=True)
# 精选景点
is_top = self.request.GET.get('is_top', None)
if is_top:
query = query & Q(is_top=True)
queryset=Sight.objects.filter(query)
return queryset

def render_to_response(self, context, **response_kwargs):
page_obj=context['page_obj']
data = {
'meta': {
'total_count':page_obj.paginator.count,
'page_count':page_obj.paginator.num_pages,
'current_page':page_obj.number,
},
'objects': []
}
for item in page_obj.object_list:
data['objects'].append({
'id':item.id,
'name':item.name,
'main_img':item.main_img.url,
'score':item.score,
'province':item.province,
'min_price':item.min_price,
'city':item.city,
'comment_count':0
})
return JsonResponse(data)

测试

Vue+Django 旅游网项目 首页后端实现_django_08

轮播图接口对接

Vue+Django 旅游网项目 首页后端实现_vue.js_09

ajax.js

import axios from 'axios'

export const ajax = axios.create({
headers: {
source: 'h5',
icode: 'acbd',
'Content-Type': 'application/x-www-form-urlencoded'
},
withCredentials: true
})
ajax.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
console.log('请求拦截到了')
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})

ajax.interceptors.response.use(function (response) {
// 对响应数据做点什么
console.log('响应拦截到了')
return response
}, function (error) {
// 对响应错误做点什么
if (error.response) {
if (error.response.status === 401) {
window.alert('未登录,即将跳转到登录页面')
} else if (error.response.status === 500) {
window.alert('服务器正忙,请稍后重试')
}
}
return Promise.reject(error)
})

apis.js

// 存放项目中所有的接口地址

const apiHost = 'http://localhost:8080/api'
const AccountsApis = {
loginUrl: '/',
logoutUrl: ''
}

/**
* 系统模块接口
*/
const SystemApis = {
sliderListUrl: apiHost + '/system/slider/list/'
}

export {
AccountsApis,
SystemApis
}

Vue+Django 旅游网项目 首页后端实现_ide_10

vue.config.js

module.exports = {
devServer:{
proxy: {
'/api': {
target:'http://127.0.0.1:8000/',
changeOrigin: true,
pathRewrite: {
'^/api': '' //需要rewrite重写的URL
}
}
}
}
}

banner组件

<template>
<!-- 轮播图 -->
<div class="home-banner-box">
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item v-for="item in bannerList"
:key="item.id">
<img :src="item.img_url" alt="">
</van-swipe-item>
</van-swipe>
</div>
</template>
<script>
import { ajax } from '@/utils/ajax'
import { SystemApis } from '@/utils/apis'
export default {
data () {
return {
bannerList: []
}
},
methods: {
/**
* 获取轮播图数据
*/
getDataList () {
ajax.get(SystemApis.sliderListUrl).then(res => {
console.log('res', res)
this.bannerList = res.data.objects
})
}
},
created () {
this.getDataList()
}
}
</script>
<style lang="less">
.home-banner-box {
img {
width: 100%;
height: auto;
}
}
</style>

效果:

Vue+Django 旅游网项目 首页后端实现_python_11

景点列表接口对接

apis.js

// 存放项目中所有的接口地址

const apiHost = 'http://localhost:8080/api'
const AccountsApis = {
loginUrl: '/',
logoutUrl: ''
}

/**
* 系统模块接口
*/
const SystemApis = {
// 轮播图列表
sliderListUrl: apiHost + '/system/slider/list/'
}

/**
* 景点模块
*/
const SightApis = {
// 景点列表
sightListUrl: apiHost + '/sight/sight/list/'
}
export {
AccountsApis,
SystemApis,
SightApis
}

组件Fine.vue

<template>
<!-- 精选景点 -->
<div class="home-fine-box">
<!-- 导航 -->
<van-cell
icon="location-o"
title="热门推荐"
title-style="text-align:left"
value="全部榜单"
is-link />
<!-- 列表 -->
<div class="box-main">
<SightItem v-for="item in dataList"
:key="item.id"
:item="item"/>
</div>
</div>
</template>
<script>
import { ajax } from '@/utils/ajax'
import { SightApis } from '@/utils/apis'
import SightItem from '@/components/common/ListSight'
export default {
components: {
SightItem
},
data () {
return {
dataList: []
}
},
methods: {
getDataList () {
ajax.get(SightApis.sightListUrl, {
params: {
is_top: 1
}
}).then(({ data }) => {
this.dataList = data.objects
})
}
},
created () {
this.getDataList()
}
}
</script>
<style lang="less">
.home-fine-box {
padding: 0 10px;
.van-cell {
padding: 10px 0;
}
.box-main {
padding-bottom: 50px;
}
}
</style>

Hot.vue

<template>
<div class="home-hot-box">
<!-- 导航 -->
<van-cell
icon="/static/home/hot/fire.png"
title="热门推荐"
title-style="text-align:left"
value="全部榜单"
is-link />
<!-- 列表 -->
<div class="box-main">
<a href="#" class="hot-item"
v-for="item in dataList"
:key="item.id">
<div class="img">
<span></span>
<img :src="item.main_img" alt="">
</div>
<h5 class="van-ellipsis">{{ item.name }}</h5>
<div class="line-price">
<span class="price">¥{{ item.min_price }}</span>起
</div>
</a>
</div>
</div>
</template>
<script>
import { ajax } from '@/utils/ajax'
import { SightApis } from '@/utils/apis'
export default {
data () {
return {
dataList: []
}
},
methods: {
getDataList () {
ajax.get(SightApis.sightListUrl, {
params: {
is_hot: 1
}
}).then(({ data }) => {
this.dataList = data.objects
})
}
},
created () {
// 查询接口数据
this.getDataList()
}
}
</script>
<style lang="less">
.home-hot-box {
padding: 0 10px;
.van-cell {
padding: 10px 0;
}
.box-main {
width: 100%;
display: flex;
padding-top: 10px;
overflow-x: scroll;
}
.hot-item {
display: flex;
flex-direction: column;
width: 100px;
margin-right: 10px;
padding-bottom: 10px;

.img {
position: relative;

span {
position: absolute;
left: 0;
top: 0;
display: inline-block;
width: 42px;
height: 20px;
z-index: 10;
}

img {
width: 100px;
height: 100px;
}
}

h5 {
color: #212121;
padding: 2px 0;
font-size: 12px;
margin: 0;
}

.line-price {
color: #212121;
font-size: 12px;
.price {
color: #f50;
font-size: 13px;
}
}
&:nth-child(1) .img span {
background: url(/static/home/hot/top1.png) no-repeat;
background-size: 100% auto;
}
&:nth-child(2) .img span {
background: url(/static/home/hot/top2.png) no-repeat;
background-size: 100% auto;
}
&:nth-child(3) .img span {
background: url(/static/home/hot/top3.png) no-repeat;
background-size: 100% auto;
}
}
}
</style>

效果:

Vue+Django 旅游网项目 首页后端实现_django_12