drf----过滤组件&分页组件的快速使用,后端drf+前端vue

0. 准备

a. django2.2+drf+vue+跨域+ide(pycharm)

b. 跨域

实现前后端跨域

前后端实现跨域https://blog.csdn.net/qq_52385631/article/details/122736816?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164398650116780271539703%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=164398650116780271539703&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-122736816.nonecase&utm_term=%E8%B7%A8%E5%9F%9F&spm=1018.2226.3001.4450c. element-ui+axios安装以及使用

element-ui+axios的使用https://blog.csdn.net/qq_52385631/article/details/122677133?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164398666516780265485172%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=164398666516780265485172&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-122677133.nonecase&utm_term=vue&spm=1018.2226.3001.4450

一. 前端配置

a. 根据上述文章,进行跨域的配置以及element-ui,axios的安装

b. 清除HelloWord和其相关的内容(为了节目效果,根路由是我们的界面)

c.  设置vue快捷启动

 

 二. 后端接口(基础接口)

a. model.py

from django.db import models


# Create your models here.

class Category(models.Model):
    category = models.CharField(verbose_name='标题', max_length=11)
    uid = models.CharField(max_length=32, verbose_name='index', help_text='element-ui的index需要一个str')

    def __str__(self):
        return self.category


class Moves(models.Model):
    title = models.CharField(verbose_name='标题', max_length=32)
    category = models.ForeignKey(verbose_name='分类', to=Category, on_delete=models.DO_NOTHING)

b. urls.py

    path('text/', views.FilterPageListAPIView.as_view()),

c. view.py

from django.shortcuts import render

from . import models
from . import serializer

from rest_framework.generics import ListAPIView


class FilterPageListAPIView(ListAPIView):
    queryset = models.Category.objects.all()
    serializer_class = serializer.FilterPageModelSerializer

d. serializer.py

from rest_framework import serializers
from .views import models


class FilterPageModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Category
        fields = '__all__'

e. 测试接口(导航栏组件,index必须是str类型,id不能满足,使用我在数据库新增了一个uid,str类型)

<template>
  <div style="width: 560px;margin: 0 auto">
    <el-menu
      :default-active="activeIndex2"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b">
      <el-menu-item :index="val.uid" v-for="(val,index) in category_data"
                    v-model="category_id"
                    :key="val.id">{{ val.category }}
      </el-menu-item>

    </el-menu>

  </div>
</template>

<script>
export default {
  name: "FilterPage",
  data() {
    return {
      // 默认选中
      activeIndex2: '1',
      // 用来接受后端的数据
      category_data: [],
      // 参数
      filter_dic: {},
    };
  },
  created() {
    // 一般在create里面进行异步请求
    this.get_category_data();
  },
  methods: {
    // 跳转路由
    handleSelect(key, keyPath) {
      // key:index,keyPath:路径
      console.log(key, keyPath);
    },
    // 定义获取分类的函数
    get_category_data() {
      // 发送请求
      this.$axios.get(`${this.$settings.host}/text/`, {
        params: {}  // 此参数必须是字典,第二种传参方式,类似于直接在路由上?username='xx'
      })
        .then((res) => {
          // 成功之后执行
          this.category_data = res.data
        }).catch((errors) => {
      })
    },

  }
}

</script>

<style scoped>

</style>

f. 测试截图

 

三. 过滤

1. 在当前项目中安装 字段过滤排序

pip install django-filter

2. 在settings.py配置文件中增加过滤后端的设置:

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要注册应用,
]

3. 视图中使用

from django.shortcuts import render

from . import models
from . import serializer
from rest_framework.generics import ListAPIView

# 1. 导包过滤组件
from django_filters.rest_framework import DjangoFilterBackend


class MovesListAPIView(ListAPIView):
    """电影视图"""
    queryset = models.Moves.objects.all()
    serializer_class = serializer.MovesModelSerializer
    # 2. 配置顾虑使用的范围
    filter_backends = [DjangoFilterBackend, ]
    # 3. 配置过滤字段(以什么字段过滤)
    filter_fields = ('category',)

4.sealizer.py

class MovesModelSerializer(serializers.ModelSerializer):
    # 利用source字段
    category_name = serializers.CharField(source='category.category')
    category_uid = serializers.CharField(source='category.uid')

    class Meta:
        model = models.Moves
        fields = ['id', 'title', 'category_name', 'category_uid']

5.url

    path('filter_text/', views.MovesListAPIView.as_view()),

ps:不清楚source字段的,这边来

序列化器中自定义外键返回值icon-default.png?t=M0H8https://blog.csdn.net/qq_52385631/article/details/122786527?spm=1001.2014.3001.55016. 前端发送请求获取数据

<template>
  <div style="width: 560px;margin: 0 auto">
    <!--分类-->
    <el-menu
      :default-active="activeIndex2"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b">
      <el-menu-item
        :index="val.uid" v-for="(val,index) in category_data"
        :key="val.id">{{ val.category }}
      </el-menu-item>
    </el-menu>
    <!--  moves列表页  -->
    <el-card class="box-card" shadow="hover" v-for="(m_val,m_index) in moves_data" :key="m_val.id">
      <div class="text item">
        <div>序号:{{ m_val.category_uid }}</div>
        <div>名称:{{ m_val.title }}</div>
        <div>分类:{{ m_val.category_name }}</div>
      </div>
    </el-card>

  </div>
</template>

<script>
export default {
  name: "FilterPage",
  data() {
    return {
      // 默认选中
      activeIndex2: '1',
      // 用来接受后端的数据
      category_data: [],
      moves_data: [],
      // 参数
      filter_dic: {},
    };
  },
  created() {
    // 一般在create里面进行异步请求
    this.get_category_data();
    this.get_moves();

  },
  methods: {
    // 跳转路由
    handleSelect(key, keyPath) {
      // key:index,keyPath:路径
      if (key === '1') {
        // uid===1为全部
        delete this.filter_dic['category']
        this.get_moves();
      } else {
        // 在字典中的封装数据
        this.filter_dic.category = key
        this.get_moves();
      }

    },
    // 定义获取分类的函数
    get_category_data() {
      // 发送请求
      this.$axios.get(`${this.$settings.host}/text/`, {
        params: {}  // 此参数必须是字典,第二种传参方式,类似于直接在路由上?username='xx'
      })
        .then((res) => {
          // 成功之后执行
          this.category_data = res.data
        }).catch((errors) => {
      })
    },

    // 获取moves
    get_moves() {
      // 发送请求
      this.$axios.get(`${this.$settings.host}/filter_text/`, {
        params: this.filter_dic  // 此参数必须是字典,第二种传参方式,类似于直接在路由上?username='xx'
      })
        .then((res) => {
          // 成功之后执行
          this.moves_data = res.data
        }).catch((errors) => {
      })
    },


  }
}

</script>

<style scoped>
.text {
  font-size: 14px;
}

.item {
  padding: 18px 0;
}

.box-card {
  width: 480px;
}
</style>

四:过滤+分页

1. element-ui分页属性介绍

Attributes(属性)

total总条目数number
layout组件布局,子组件名用逗号分隔Stringsizesprevpagernextjumper->totalslot'prev, pager, next, jumper, ->, total'
page-sizes每页显示个数选择器的选项设置number[][10, 20, 30, 40, 50, 100]

Events(事件)

事件名称说明回调参数
size-changepageSize 改变时会触发每页条数
current-changecurrentPage 改变时会触发当前页

2.后端接口

url

    path('filter_text/', views.MovesListAPIView.as_view()),

view

from django.shortcuts import render

from . import models
from . import serializer
from rest_framework.generics import ListAPIView

# 1. 导包过滤组件
from django_filters.rest_framework import DjangoFilterBackend
# 导入分页组件(restframework自带的)
from rest_framework.pagination import PageNumberPagination


class MyPageNumberPagination(PageNumberPagination):
    page_size = 5  # 每页显示的个数
    page_query_param = 'page'  # 查询参数 ?page=3
    page_size_query_param = 'size'  # 前端自定义查询的数量,?size=10
    max_page_size = 100  # 前端自定义显示的字段条数的最大限制


class MovesListAPIView(ListAPIView):
    """电影视图"""
    queryset = models.Moves.objects.all()
    serializer_class = serializer.MovesModelSerializer
    # 2. 配置顾虑使用的范围
    filter_backends = [DjangoFilterBackend, ]
    # 3. 配置过滤字段(以什么字段过滤)
    filter_fields = ('category',)
    # 分页配置
    pagination_class = MyPageNumberPagination

serializer

from rest_framework import serializers
from .views import models


class MovesModelSerializer(serializers.ModelSerializer):
    # 利用source字段
    category_name = serializers.CharField(source='category.category')
    category_uid = serializers.CharField(source='category.uid')

    class Meta:
        model = models.Moves
        fields = ['id', 'title', 'category_name', 'category_uid']

前端

<template>
  <div style="width: 560px;margin: 0 auto">
    <!--分类-->
    <el-menu
      :default-active="activeIndex2"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b">
      <el-menu-item
        :index="val.uid" v-for="(val,index) in category_data"
        :key="val.id">{{ val.category }}
      </el-menu-item>
    </el-menu>
    <!--    分页-->
    <div>
      <el-pagination
        @size-change="handleSizeChange"
        :page-sizes="[5, 8, 10, 20]"
        @current-change="handleCurrentChange"
        background
        layout="total, sizes, prev, pager, next, jumper"
        :page-size="5"
        :total="totals">
      </el-pagination>
    </div>
    <!--  moves列表页  -->
    <el-card class="box-card" shadow="hover" v-for="(m_val,m_index) in moves_data" :key="m_val.id">
      <div class="text item">
        <div>序号:{{ m_val.category_uid }}</div>
        <div>名称:{{ m_val.title }}</div>
        <div>分类:{{ m_val.category_name }}</div>
      </div>
    </el-card>

  </div>
</template>

<script>
export default {
  name: "FilterPage",
  data() {
    return {
      // 默认选中
      activeIndex2: '1',
      // 用来接受后端的数据
      category_data: [],
      moves_data: [],
      // 参数
      filter_dic: {},
      totals: 0,
    };
  },
  created() {
    // 一般在create里面进行异步请求
    this.get_category_data();
    this.get_moves();

  },
  methods: {
    // 跳转路由
    handleSelect(key, keyPath) {
      // key:index,keyPath:路径
      if (key === '1') {
        // uid===1为全部
        delete this.filter_dic['category']
        this.get_moves();
      } else {
        // 在字典中的封装数据
        this.filter_dic.category = key
        this.get_moves();
      }

    },
    // 定义获取分类的函数
    get_category_data() {
      // 发送请求
      this.$axios.get(`${this.$settings.host}/text/`, {
        params: {}  // 此参数必须是字典,第二种传参方式,类似于直接在路由上?username='xx'
      })
        .then((res) => {
          // 成功之后执行
          this.category_data = res.data
        }).catch((errors) => {
      })
    },

    // 获取moves
    get_moves() {
      // 发送请求
      this.$axios.get(`${this.$settings.host}/filter_text/`, {
        params: this.filter_dic  // 此参数必须是字典,第二种传参方式,类似于直接在路由上?username='xx'
      })
        .then((res) => {
          // 成功之后执行
          // this.moves_data = res.data
          // 现在的数据在data.results里面,必须进行修改,不然会报name...这个错
          this.moves_data = res.data.results
          // 总页码数
          this.totals = res.data.count
        }).catch((errors) => {
      })
    },
    // 点击页码触发函数
    handleCurrentChange(cpage) {
      // cpage:当前页码数
      this.filter_dic.page = cpage
      this.get_moves();
    },
    // 自定义展示数据
    handleSizeChange(size) {
      this.filter_dic.size = size
      this.get_moves();
    }
  }
}

</script>

<style scoped>
.text {
  font-size: 14px;
}

.item {
  padding: 18px 0;
}

.box-card {
  width: 480px;
}
</style>

效果截图

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本门课程重实战,将基础知识拆解到项目里,让你在项目情境里学知识。 这样的学习方式能让你保持兴趣、充满动力,时刻知道学的东西能用在哪、能怎么用。 平时不明白的知识点,放在项目里去理解就恍然大悟了。 &nbsp; 一、融汇贯通 本视频采用了前后端分离的开发模式,前端使用Vue.js+Element UI实现了Web页面的呈现,后端使用Python 的Django框架实现了数据访问的接口,前端通过Axios访问后端接口获得数据。在学习完本章节后,真正理解前后端的各自承担的工作。 &nbsp; 二、贴近实战 本系列课程为练手项目实战:学生管理系统v4.0的开发,项目包含了如下几个内容:项目的总体介绍、基本功能的演示、Vuejs的初始化、Element UI的使用、在Django中实现针对数据的增删改查的接口、在Vuejs中实现前端增删改查的调用、实现文件的上传、实现表格的分页、实现导出数据到Excel、实现通过Excel导入数据、实现针对表格的批量化操作等等,所有的功能都通过演示完成、贴近了实战 &nbsp; 三、课程亮点 在本案例中,最大的亮点在于前后端做了分离,真正理解前后端的各自承担的工作。前端如何和后端交互 &nbsp; 适合人群: 1、有Python语言基础、web前端基础,想要深入学习Python Web框架的朋友; 2、有Django基础,但是想学习企业级项目实战的朋友; 3、有MySQL数据库基础的朋友 &nbsp;
以下是一个使用 Django Rest Framework (DRF)、Vue 3 和 Element Plus 搭建的前后端分离模板。 ### 后端 (Django Rest Framework) 1. 创建一个 Django 项目和应用程序: ``` $ django-admin startproject myproject $ cd myproject $ python manage.py startapp myapp ``` 2. 安装 DRF: ``` $ pip install djangorestframework ``` 3. 在 `myproject/settings.py` 中添加 DRF 和 CORS 的配置: ```python INSTALLED_APPS = [ # ... &#39;rest_framework&#39;, ] MIDDLEWARE = [ # ... &#39;corsheaders.middleware.CorsMiddleware&#39;, &#39;django.middleware.common.CommonMiddleware&#39;, ] REST_FRAMEWORK = { &#39;DEFAULT_AUTHENTICATION_CLASSES&#39;: ( &#39;rest_framework.authentication.TokenAuthentication&#39;, &#39;rest_framework.authentication.SessionAuthentication&#39;, ), &#39;DEFAULT_PERMISSION_CLASSES&#39;: ( &#39;rest_framework.permissions.IsAuthenticated&#39;, ), } CORS_ORIGIN_ALLOW_ALL = True ``` 4. 在 `myapp/views.py` 中定义一个视图: ```python from rest_framework.decorators import api_view from rest_framework.response import Response @api_view([&#39;GET&#39;]) def hello(request): return Response({&#39;message&#39;: &#39;Hello, world!&#39;}) ``` 5. 在 `myproject/urls.py` 中添加路由: ```python from django.urls import path, include from myapp.views import hello urlpatterns = [ path(&#39;api/&#39;, include([ path(&#39;hello/&#39;, hello), ])), ] ``` 6. 运行服务器: ``` $ python manage.py runserver ``` 访问 `http://localhost:8000/api/hello/` 应该会返回 `{&quot;message&quot;: &quot;Hello, world!&quot;}`。 ### 前端 (Vue 3 + Element Plus) 1. 使用 Vue CLI 创建一个新项目: ``` $ vue create myproject-frontend ``` 2. 安装 Element Plus: ``` $ npm install element-plus --save ``` 3. 在 `main.js` 中引入 Element Plus 和样式: ```javascript import { createApp } from &#39;vue&#39; import App from &#39;./App.vue&#39; import ElementPlus from &#39;element-plus&#39; import &#39;element-plus/lib/theme-chalk/index.css&#39; createApp(App) .use(ElementPlus) .mount(&#39;#app&#39;) ``` 4. 在 `App.vue` 中添加一个按钮和一个文本框: ```vue &lt;template&gt; &lt;div class=&quot;container&quot;&gt; &lt;el-input v-model=&quot;name&quot; placeholder=&quot;Enter your name&quot;&gt;&lt;/el-input&gt; &lt;el-button type=&quot;primary&quot; @click=&quot;sayHello&quot;&gt;Say hello&lt;/el-button&gt; &lt;div class=&quot;result&quot;&gt;{{ result }}&lt;/div&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; import axios from &#39;axios&#39; export default { name: &#39;App&#39;, data() { return { name: &#39;&#39;, result: &#39;&#39; } }, methods: { sayHello() { axios.get(&#39;/api/hello/&#39;, { headers: { &#39;Authorization&#39;: &#39;Token &#39; + sessionStorage.getItem(&#39;token&#39;) } }) .then(response =&gt; { this.result = response.data.message }) .catch(error =&gt; { console.error(error) }) } } } &lt;/script&gt; &lt;style&gt; .container { max-width: 800px; margin: 0 auto; padding: 20px; } .result { margin-top: 20px; font-weight: bold; } &lt;/style&gt; ``` 5. 运行服务器: ``` $ npm run serve ``` 访问 `http://localhost:8080/` 应该会显示一个文本框和一个按钮。在文本框中输入你的名字,然后点击按钮,应该会显示 `Hello, world!`。 这是一个简单的模板,你可以根据自己的需要进行扩展和定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑猪去兜风z1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值