美文网首页Django+Vue生鲜电商
【Vue+DRF生鲜电商】23.个人中心用户留言功能

【Vue+DRF生鲜电商】23.个人中心用户留言功能

作者: 吾星喵 | 来源:发表于2019-06-19 14:18 被阅读18次

    专题:Vue+Django REST framework前后端分离生鲜电商

    Vue+Django REST framework 打造前后端分离的生鲜电商项目(慕课网视频)。
    Github地址:https://github.com/xyliurui/DjangoOnlineFreshSupermarket
    Django版本:2.2、djangorestframework:3.9.2。

    更多内容请点击 我的博客 查看,欢迎来访。

    用户留言功能

    BLOG_20190619_141603_61

    留言分为以上5中类型,支持上传文件。

    现有的留言models如下,需要的字段都是齐全的

    class UserLeavingMessage(models.Model):
        """
        用户留言
        """
        MESSAGE_TYPE = (
            (1, '留言'),
            (2, '投诉'),
            (3, '询问'),
            (4, '售后'),
            (5, '求购')
        )
        user = models.ForeignKey(User, verbose_name='用户', help_text='用户', on_delete=models.CASCADE, related_name='leaving_msgs')
        message_type = models.IntegerField(default=1, choices=MESSAGE_TYPE, verbose_name='留言类型', help_text='留言类型:1-留言,2-投诉, 3-询问, 4-售后, 5-求购')
        subject = models.CharField(max_length=100, default='', verbose_name='主题', help_text='主题')
        message = models.TextField(default='', verbose_name='留言内容', help_text='留言内容')
        file = models.FileField(upload_to='upload/leaving_msg/', blank=True, null=True, verbose_name='上传文件', help_text='上传文件')
        add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
    
        class Meta:
            verbose_name_plural = verbose_name = '用户留言'
    
        def __str__(self):
            return '{} {}:{}'.format(self.user.name if self.user.name else self.user.username, self.get_message_type_display(), self.subject)
    

    序列化用户留言UserLeavingMessageSerializer

    在 apps/user_operation/serializers.py 添加一个 UserLeavingMessageSerializer 用于序列化用户留言

    from .models import UserFav, UserLeavingMessage
    
    
    class UserLeavingMessageSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()  # 表示user为隐藏字段,默认为获取当前登录用户
        )
    
        class Meta:
            model = UserLeavingMessage
            fields = ['user', 'message_type', 'subject', 'message', 'file', 'add_time']
    

    用户留言功能视图UserLeavingMessageViewSet

    首先引入该models和serializer

    from .serializers import UserFavSerializer, UserFavListSerializer, UserLeavingMessageSerializer
    from .models import UserFav, UserLeavingMessage
    
    class UserLeavingMessageViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
        """
        create:
            创建用户留言
    
        list:
            获取用户留言
    
        delete:
            删除用户留言
        """
        queryset = UserLeavingMessage.objects.all()
        serializer_class = UserLeavingMessageSerializer
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)  # 用户必须登录才能访问
        authentication_classes = (JWTAuthentication, SessionAuthentication)  # 配置登录认证:支持JWT认证和DRF基本认证
    
        def get_queryset(self):
            """只查询当前登录用户"""
            return self.queryset.filter(user=self.request.user)
    

    注册用户留言url

    修改 DjangoOnlineFreshSupermarket/urls.py 添加router

    from user_operation.views import UserFavViewSet, UserLeavingMessageViewSet
    
    # ......
    router.register(r'livingmsgs', UserLeavingMessageViewSet, base_name='livingmsgs')  # 用户留言
    

    访问 http://127.0.0.1:8000/docs/#livingmsgs-list 后台文档,可以看到留言的三个功能

    BLOG_20190619_141551_80

    因为必须要在登录状态下,可以选择session去认证

    BLOG_20190619_141546_89

    但是创建留言并没有上传文件的功能,这儿选择DRF Api来完成

    访问 http://127.0.0.1:8000/livingmsgs/ 可以看到下面的内容

    BLOG_20190619_141539_37

    Vue中显示用户留言

    留言组件在 src/views/member/message.vue 中,当组件创建时

            created() {
                this.getMessage();
            },
    

    调用getMessage()函数

                getMessage() { //获取留言
                    getMessages().then((response) => {
                        console.log(response.data);
                        this.messageAll = response.data;
                    }).catch(function (error) {
                        console.log(error);
                    });
                },
    

    通过api src/api/api.js 请求后端

    //获取留言
    export const getMessages = () => {
        return axios.get(`${local_host}/livingmsgs/`)
    };
    
    //添加留言
    export const addMessage = params => {
        return axios.post(`${local_host}/livingmsgs/`, params, {headers: {'Content-Type': 'multipart/form-data'}})
    };
    
    //删除留言
    export const delMessages = messageId => {
        return axios.delete(`${local_host}/livingmsgs/` + messageId + '/')
    };
    

    src/views/member/message.vue 将请求结果展示出来

        <li v-for="(item,index) in messageAll">
            <div>
                <span v-if="item.message_type===1">留言:</span>
                <span v-if="item.message_type===2">投诉:</span>
                <span v-if="item.message_type===3">询问:</span>
                <span v-if="item.message_type===4">售后:</span>
                <span v-if="item.message_type===5">求购:</span>
                <span>{{item.subject}}</span>
                <span>({{item.add_time}})</span>
            </div>
            <div>
                {{item.message}}
            </div>
            <div>
                <a @click="deleteMessage(index, item.id)">删除</a>
                <a :href="(item.file)">查看上传的文件</a>
    
            </div>
        </li>
    

    BLOG_20190619_141528_67

    DRF Api中测试留言上传文件

    访问 http://127.0.0.1:8000/livingmsgs/ 添加留言同时上传文件

    BLOG_20190619_141520_68

    然后点击POST提交,可以看到返回的数据

    BLOG_20190619_141504_82

    其中包括file字段,里面是文件的完整路径

    再次访问 http://127.0.0.1:8000/livingmsgs/ 可以查看它的get请求

    BLOG_20190619_141439_85

    其中file也是完整的url

    前端访问 http://127.0.0.1:8080/#/app/home/member/message

    BLOG_20190619_141432_19

    点击“查看上传的文件”可以看到会自动跳转到文件浏览。

    格式化显示日期时间

    但是这个时间显示太丑了,进行格式化

    修改 apps/user_operation/serializers.py 中的UserLeavingMessageSerializer,指定add_time

    class UserLeavingMessageSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()  # 表示user为隐藏字段,默认为获取当前登录用户
        )
        add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')  # read_only序列化只返回不提交,format指定格式化
    
        class Meta:
            model = UserLeavingMessage
            fields = ['user', 'message_type', 'subject', 'message', 'file', 'add_time']
    

    访问 http://127.0.0.1:8000/livingmsgs/ 可以看到时间已被正常序列化

    BLOG_20190619_141426_54

    用户留言删除

    在 src/views/member/message.vue 中删除用户留言需要给定该对象的id

    <a @click="deleteMessage(index, item.id)">删除</a>
    

    而在做序列化时并没有显示出来,现在修改 apps/user_operation/serializers.py 为UserLeavingMessageSerializer添加id字段

    class UserLeavingMessageSerializer(serializers.ModelSerializer):
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()  # 表示user为隐藏字段,默认为获取当前登录用户
        )
    
        class Meta:
            model = UserLeavingMessage
            fields = ['id', 'user', 'message_type', 'subject', 'message', 'file', 'add_time']
    

    BLOG_20190619_141417_12

    可以看到id已被显示出来

    访问 http://127.0.0.1:8080/#/app/home/member/message 点击某一条留言的“删除”

    BLOG_20190619_141412_11

    该留言就直接被删除了。

    删除功能在 src/views/member/message.vue 中

                deleteMessage(index, id) { // 删除留言
                    delMessages(id).then((response) => {
                        alert("删除成功");
                        this.messageAll.splice(index, 1);
                    }).catch(function (error) {
                        console.log(error);
                    });
                },
    

    用户留言创建

    创建留言的表单在 src/views/member/message.vue

    <form action="" method="post" enctype="multipart/form-data" name="formMsg">
        <table width="100%" border="0" cellpadding="3">
            <tbody>
            <tr>
                <td align="right">留言类型:</td>
                <td>
                    <input type="radio" id="one" value="1" v-model="message_type">
                    <label for="one">留言</label>
                    <input type="radio" id="two" value="2" v-model="message_type">
                    <label for="two">投诉</label>
                    <input type="radio" id="three" value="3" v-model="message_type">
                    <label for="three">询问</label>
                    <input type="radio" id="four" value="4" v-model="message_type">
                    <label for="four">售后</label>
                    <input type="radio" id="five" value="5" v-model="message_type">
                    <label for="five">求购</label>
                </td>
            </tr>
            <tr>
                <td align="right">主题:</td>
                <td><input name="msg_title" type="text" size="30" class="inputBg" v-model="subject"></td>
            </tr>
            <tr>
                <td align="right" valign="top">留言内容:</td>
                <td><textarea name="msg_content" cols="50" rows="4" wrap="virtual" class="B_blue" v-model="message"></textarea></td>
            </tr>
            <tr>
                <td align="right">上传文件:</td>
                <td><input type="file" name="message_img" size="45" class="inputBg" @change="preview"></td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><input type="hidden" name="act" value="act_add_message">
                    <a class="btn_blue_1" @click="submitMessage">提交</a>
                </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>
                    <font color="red">小提示:</font><br>
                    您可以上传以下格式的文件:<br>gif、jpg、png、word、excel、txt、zip、ppt、pdf
                </td>
            </tr>
            </tbody>
        </table>
    </form>
    

    BLOG_20190619_141404_10

    当用户点击“提交”,会调用submitMessage函数

        preview(e) {
            this.file = e.target.files[0]; //获取文件资源
            console.log(this.file);
    
        },
        submitMessage() { //提交留言
            const formData = new FormData();
            formData.append('file', this.file);
            formData.append('subject', this.subject);
            formData.append('message', this.message);
            formData.append('message_type', this.message_type);
            addMessage(formData).then((response) => {
                this.getMessage();
    
            }).catch(function (error) {
                console.log(error);
            });
        },
    

    获取表单保存在formData中,addMessage提交到后端

    也就是直接调用 src/api/api.js 中的addMessage

    //添加留言
    export const addMessage = params => {
        return axios.post(`${local_host}/livingmsgs/`, params, {headers: {'Content-Type': 'multipart/form-data'}})
    };
    

    上传文件测试

    BLOG_20190619_141355_93

    BLOG_20190619_141349_84

    为什么DRF支持这么轻松的上传文件?

    在DRF Api https://www.django-rest-framework.org/api-guide/parsers/#multipartparser 中可以看到

    解析多部分HTML表单内容,支持文件上传。request.data 都将被一个 QueryDict填充。

    你通常会同时使用FormParserMultiPartParser两者,以便完全支持HTML表单数据。

    .media_type: multipart/form-data

    相关文章

      网友评论

        本文标题:【Vue+DRF生鲜电商】23.个人中心用户留言功能

        本文链接:https://www.haomeiwen.com/subject/ktqkqctx.html