django4.0+vue3对接

使用corsheaders包跨域

设置参考:https://blog.csdn.net/m0_62520968/article/details/124376513?spm=1001.2014.3001.5501https://blog.csdn.net/m0_62520968/article/details/124376513?spm=1001.2014.3001.5501

Django后端,rest_framework+token登录验证,使用默认用户表

建立模型models.py

from django.db import models
from io import BytesIO
from PIL import Image
from django.core.files import File


# Create your models here.
class Category(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField()  # 仅包含数字字母下划线,常用于网址

    class Meta:
        ordering = ('name',)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return f'/{self.slug}/'


class Product(models.Model):
    category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    slug = models.SlugField()
    description = models.TextField(blank=True, null=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.ImageField(upload_to='uploads/', blank=True, null=True)
    thumbnail = models.ImageField(upload_to='uploads/', blank=True, null=True)
    date_add = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ('-date_add',)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return f'/{self.category.slug}/{self.slug}/'

    def get_image(self):
        if self.image:
            return 'http://127.0.0.1:8000' + self.image.url
        return ''

    def get_thumbnail(self):
        if self.thumbnail:
            return 'http://127.0.0.1:8000' + self.thumbnail.url
        else:
            if self.image:
                self.thumbnail = self.make_thumbnail(self.image)
                self.save()

                return 'http://127.0.0.1:8000' + self.thumbnail.url
            else:
                return ''

    def make_thumbnail(self, image, size=(300, 200)):
        img = Image.open(image)
        img.convert('RGB')
        img.thumbnail(size)

        thumb_io = BytesIO()
        img.save(thumb_io, 'JPEG', quality=85)

        thumbnail = File(thumb_io, name=image.name)

        return thumbnail

模型序列化serializers.py

from rest_framework import serializers

from .models import *


class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = (
            'id',
            'name',
            'get_absolute_url',
            'description',
            'price',
            'get_image',
            'get_thumbnail',

        )

class CategorySerializer(serializers.ModelSerializer):
    # Category是Product的外键,这样可以调用Product序列化的数据
    products = ProductSerializer(many=True)

    class Meta:
        model = Category
        fields = (
            'id',
            'name',
            'get_absolute_url',
            'products',
        )

视图函数view.py

from django.db.models import Q
from django.http import Http404
from django.shortcuts import render
from .serializers import *
from rest_framework.views import APIView
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import *


# Create your views here.
class LatestProductList(APIView):
    def get(self, request, format=None):
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data)


class ProductDetail(APIView):
    def get_object(self, category_slug, product_slug):
        try:
            return Product.objects.filter(category__slug=category_slug).get(slug=product_slug)
        except Product.DoesNotExist:
            raise Http404

    def get(self, request, category_slug, product_slug, format=None):
        product = self.get_object(category_slug, product_slug)
        serializer = ProductSerializer(product)
        return Response(serializer.data)


class CategoryDetail(APIView):
    def get_object(self, category_slug):
        try:
            return Category.objects.get(slug=category_slug)
        except Product.DoesNotExist:
            raise Http404

    def get(self, request, category_slug, format=None):
        category = self.get_object(category_slug)
        serializer = CategorySerializer(category)
        return Response(serializer.data)


@api_view(['POST'])
def search(request):
    query = request.data.get('query', '')

    if query:
        products = Product.objects.filter(Q(name__icontains=query) | Q(description__icontains=query))
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data)

    else:
        return Response({'products': []})

主urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static  # static函数添加静态文件

urlpatterns = [
                  path('admin/', admin.site.urls),
                  path('api/v1/', include('djoser.urls')),
                  path('api/v1/', include('djoser.urls.authtoken')),
                  path('api/v1/', include('products.urls'), name='products'),
              ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

应用urls.py

from django.urls import path, include
from products import views
urlpatterns = [
    path('latest-products/', views.LatestProductList.as_view(), name='latest-products'),
    path('products/search/', views.search),
    path('products///', views.ProductDetail.as_view()),
    path('products//', views.CategoryDetail.as_view()),
]

Vue3:

图标引入:public->index.html

      
    

main.js设置默认访问url:axios.defaults.baseURL

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from "axios"

axios.defaults.baseURL = `http://127.0.0.1:8000`

createApp(App).use(store).use(router, axios).mount('#app')

 在views创建视图HomeView.vue   ProductView.vue......

 router->index.js加入设置路由,导入视图,默认进入home,对某个视图进行权限认证增加

meta:{
  requireLogin:true
}
router.beforeEach对每个视图检验权限,无权限的自动进入home,有权限的放行
import HomeView from '../views/HomeView.vue'
import ProductView from "../views/ProductView.vue";
import Category from "@/views/Category";
import Search from "@/views/Search";
import SignUp from "@/views/SignUp";
import Login from "@/views/Login";
import MyAccount from "@/views/MyAccount";
const routes = [
{
    path: '/',
    name: 'home',
    component: HomeView
  },
{
    path: '/:category_slug/:product_slug/',
    name: 'productview',
    component: ProductView
  },
  {
    path: '/:category_slug',
    name: 'Category',
    component: Category
  },
  {
    path: '/search',
    name: 'Search',
    component: Search
  },
{
    path: '/sign-up',
    name: 'SignUp',
    component: SignUp
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  },
  {
    path: '/myaccount',
    name: 'MyAccount',
    component: MyAccount,
    meta:{
      requireLogin:true
    }
  },]
router.beforeEach((to, from, next)=>{
  if (to.matched.some(record=>record.meta.requireLogin) && !store.state.isAuthenticated) {
    next({name:'Login', query:{to:to.path}});
  }else {
    next()
  }
})

 store->index.js保存状态加入通用方法

state: {
    isAuthenticated:false,
    token:'',
    isLoading:false,
  },
  getters: {
  },
  mutations: {
    initializeStore(state){
      if (localStorage.getItem('token')){
        state.token = localStorage.getItem('token')
        state.isAuthenticated = true
      }else {
        state.token= ''
        state.isAuthenticated = false
      }
    },

    //设置加载框
    setIsLoading(state,status){
      state.isLoading = status
    },
    setToken(state, token){
      state.token = token
      state.isAuthenticated = true
    },
    removeToken(state, token){
      state.token = ''
      state.isAuthenticated = false
    },
  },

App.vue主模块,类似模板,可当做模板页面使用,其他页面都是在它基础上添加组件,需要返回渲染页面的数据在data->return声明,调用 store->index.js的初始化方法,设置ajax请求头,在'Token '+ token拼接时一定要加一个空格否则验证不通过

axios.defaults.headers.common['Authorization'] = 'Token '+ token




HomeView.vue,mounted部分在网页初始化调用,ajax的get请求及返回数据接收,url使用反引号(英文状态下的1左边的~)。一些自定义组件(例如商品介绍卡片)可以在components部分调用,但是需要在components文件夹自定义(如ProductBox组件)

HomeView.vue





components->ProductBox.vue,组件声明,

props:{
  product:Object
}

然后在其他vue里导入,就可以在页面这样调用

        v-for="product in latestProducts"//操作
        v-bind:key="product.id"
        v-bind:product="product"/>//绑定





Search.vue,post方法举例




你可能感兴趣的:(python,django,restful,vue)