Django DRF API(GET/POST/PUT)序列化和反序列化(一对多,多对多)demo-模型类序列化器ModelSerializer

news/2024/11/8 23:47:33/

一. 前言

在开发REST API接口时,视图中做的最主要有三件事:

  • 将请求的数据(如JSON格式)转换为模型类对象
  • 操作数据库
  • 将模型类对象转换为响应的数据(如JSON格式)

序列化:

将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等),例如将Django中的模型类对象装换为JSON字符串,这个转换过程我们称为序列化。
简单的一句话理解就是将数据转化为JSON格式返回给前端

反序列化:
反之,将其他格式(字典、JSON、XML等)转换为程序中的数据,例如将JSON字符串转换为Django中的模型类对象,这个过程我们称为反序列化。

总结

在开发REST API时,视图中要频繁的进行序列化与反序列化的编写。

在开发REST API接口时,我们在视图中需要做的最核心的事是:

  • 将数据库数据序列化为前端所需要的格式,并返回;
  • 将前端发送的数据反序列化为模型类对象,并保存到数据库中。

二. 环境安装配置

1. 安装DRF

pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple  djangorestframework

2. 添加rest_framework应用

INSTALLED_APPS = [...'rest_framework',
]

接下来就可以使用DRF进行开发了。

普通的序列化器这里就不介绍了,下面介绍的时进阶版的模型类序列化器-ModelSerializer
此项目使用的时前后端不分离的开发模式,本质上给前端传递数据是一样的

三. 序列化与反序列化

模型表models.py

from django.contrib.auth.models import User
from django.db import modelsfrom apps.file.models import TeamDataStructureFile
from utils.base_models import BaseModelclass DataStructure(BaseModel):CATEGORY_CHOICES = [('Knowledge Category', 'Knowledge Category'),('Knowledge Category1', 'Knowledge Category1'),]TEAM_CHOICES = [('sys-tech', 'sys-tech'),('data structure', 'data structure'),]title = models.CharField(max_length=200, verbose_name='主题', blank=False)owner = models.CharField(max_length=50,blank=True,verbose_name='申请人ID')full_name = models.CharField(max_length=50,blank=False,verbose_name='申请人')knowledge_category = models.CharField(max_length=50,blank=False,choices=CATEGORY_CHOICES,verbose_name='知识类别')team = models.CharField(max_length=50,blank=False,choices=TEAM_CHOICES,verbose_name='团队')description = models.TextField(null=True, blank=True, verbose_name='描述')# 添加user, file复合主键# 一对多user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)# 多对多attachments = models.ManyToManyField(TeamDataStructureFile, blank=True)class Meta:ordering = ['-create_time']def __str__(self):return self.title

序列化器serializers.py

from rest_framework.serializers import ModelSerializerfrom apps.file.models import TeamDataStructureFile
from apps.file.serializers import TeamDataStructureFileField
from teams.models import DataStructureclass DataStructureSerializer(ModelSerializer):"""序列化与反序列化数据时可以使用"""class Meta:model = DataStructurefields = '__all__'class EditDataStructureSerializer(ModelSerializer):"""编辑数据反序列化器"""class Meta:model = DataStructureexclude = ('attachments',)  # 若编辑文件接口提交时文件为空,此时不需要序列化此字段class TeamDataStructureQuerySerializer(ModelSerializer):"""查询所有数据的序列化器"""attachments = TeamDataStructureFileField(queryset=TeamDataStructureFile.objects.all(), many=True)class Meta:model = DataStructurefields = '__all__'

1.添加数据

视图函数views.py

class AddDataStructureView(LoginRequiredJSONMixin, APIView):def get(self, request):ds = DataStructure()knowledge_category = [i[1] for i in ds.CATEGORY_CHOICES]teams = [i[1] for i in ds.TEAM_CHOICES]context = {'add_knowledge_category': knowledge_category,'add_teams': teams,}return render(request, 'teams/data_structure/add_data_structure.html', context)@transaction.atomicdef post(self, request):"""反序列化一条数据,存入数据库"""# print(request.data)serializer = DataStructureSerializer(data=request.data)if serializer.is_valid():# serializer.ds = serializer.save()# handle filefiles_obj = request.FILES.getlist('uploadFile')if files_obj:handle_files(request, files_obj, ds, TeamFileSerializer)return api_success('信息保存成功!Data loading')return api_bad_request('表单数据输入有误,认证失败,数据无法保存!')

2.查询/编辑/删除数据

class DataStructureDetailView(LoginRequiredJSONMixin, APIView):def get(self, request, id):"""序列化器数据,并返回给前端"""ds = get_object_or_404(DataStructure, pk=id)s = DataStructureSerializer(ds)context = s.datacontext['teams'] = [i[1] for i in ds.TEAM_CHOICES if i[1] != s.data['team']]context['knowledge_categories'] = [i[1] for i in ds.CATEGORY_CHOICES if i[1] !=s.data['knowledge_category']]attachments = ds.attachments.all()initialPreviewData = []try:for file in attachments:initialPreviewData.append({'file_id': file.id,'file_url': SERVER_URL + '/' + file.file.url,'file_type': file.suffix.lower(),'file_name': file.filename,'file_size': file.file.size})except Exception as e:logger.info('get DataStructureDetailView error:{}'.format(e))context['initialPreviewData'] = initialPreviewDatacontext['user'] = ds.user# print(context)return render(request, 'teams/data_structure/edit_data_structure.html', context)@transaction.atomicdef put(self, request, id):""""反序列化数据,存入数据库"""# print(request.data)ds = get_object_or_404(DataStructure, pk=id)old_ds = copy.copy(ds)# 此处重新定义了序列化器是因为文件传过来的时候为空,所以需要重新定义新的序列化器,先处理数据,再处理文件,exclude attachments字段可使该字段在处理数据时被忽略,最后在单独处理该字段s = EditDataStructureSerializer(instance=ds, data=request.data)if s.is_valid():new_ds = s.save()# handle filefiles_obj = request.FILES.getlist('uploadFile')if files_obj:handle_files(request, files_obj, new_ds, TeamFileSerializer)# 变更差异信息# old_ds_dic = model_to_dict(old_ds)# new_ds_dic = model_to_dict(new_ds)# diff = old_ds_dic.keys() & new_ds_dic# diff_vals = [(k + ': from ' + str(old_ds_dic[k]) + ' to ' + str(new_ds_dic[k])) for k in diff if#              old_ds_dic[k] != new_ds_dic[k]]# print(diff_vals)return api_success('信息保存成功!Data loading')return api_bad_request('数据表单验证失败,无法保存!')def delete(self, request, id):# print(request, id)ds = get_object_or_404(DataStructure, pk=id)res = delete_data(ds)if res:return api_success(res)return api_bad_request('数据删除失败!')

封装的文件处理函数public.py,也是多对多外键attachments字段数据库处理的方式

def handle_files(request, files_obj, obj, FileSerializer):"""该函数传参对象有attachments属性时才可调用"""files = []for file_obj in files_obj:filename = file_obj.namesuffix = filename.rsplit(".", 1)[1]file_data = {'file': file_obj,'filename': filename,'suffix': suffix,}if request.method == 'PUT':# 1.本地文件删除obj_files = obj.attachments.all()for file in obj_files:file.file.delete()# 2.文件数据记录删除(先删除子表数据记录)obj_files.delete()fs = FileSerializer(data=file_data)if fs.is_valid():new_file = fs.save()new_file.content_object = objnew_file.save()files.append(fs.data.get('id'))if request.method == 'POST':obj.attachments.add(*files)if request.method == 'PUT':obj.attachments.set(files)def delete_data(obj):"""该函数传参对象有attachments属性时才可调用"""# 设置事务,保证数据的同步with transaction.atomic():save_point = transaction.savepoint()try:# 1.本地文件删除files = obj.attachments.all()if files:for file in files:file.file.delete()# 2.文件数据记录删除(先删除子表数据记录)files.delete()# 3.数据删除(再父表数据记录删除)obj.delete()except Exception as e:transaction.rollback(save_point)logger.info('obj->{} file delete error:{}'.format(obj, e))else:transaction.savepoint_commit(save_point)msg = '数据删除成功!Data loading......'return msgdef get_page_all_data(total, rows, sortOrder, pageNumber, pageSize):for i in range(len(rows)):if sortOrder == 'desc':no = total - (pageNumber - 1) * pageSize - ielse:no = (pageNumber - 1) * pageSize + i + 1rows[i]['no'] = nodata = {"total": total, "rows": rows}return data

3.分页查询数据处理

class DataStructureListView(APIView):def get(self, request):pageSize = int(request.GET.get('pageSize', 10))pageNumber = int(request.GET.get('pageNumber', 1))search_kw = request.GET.get('search_kw', '')sortName = request.GET.get('sortName', '')sortOrder = request.GET.get('sortOrder', '')ds_all = DataStructure.objects.all()# 查询if search_kw:ds_all = ds_all.filter(Q(title__icontains=search_kw) | Q(description__icontains=search_kw) | Q(full_name__icontains=search_kw))if sortName == 'no':sortName = 'id'# 排序if sortOrder == 'desc':ds_list = ds_all.order_by('-{}'.format(sortName))[(pageNumber - 1) * pageSize:(pageNumber) * pageSize]else:ds_list = ds_all.order_by(sortName)[(pageNumber - 1) * pageSize:(pageNumber) * pageSize]total = ds_all.count()# print(ds_list)# page_data = self.get_page_data(ds_list, total, sortOrder, pageNumber, pageSize)rows = TeamDataStructureQuerySerializer(ds_list, many=True).datapage_data = get_page_all_data(total, rows, sortOrder, pageNumber, pageSize)if page_data:return JsonResponse(page_data)return api_bad_request('数据加载失败!')def get_page_data(self, obj_list, total, sortOrder, pageNumber, pageSize):"""不使用序列化器,前端需要修改attachment字段获取方式"""ds_list_len = len(obj_list)rows = []data = {"total": total, "rows": rows}for i in range(ds_list_len):attachments = {}attachments['file_name'] = [i.filename for i in obj_list[i].attachments.all()]attachments['id'] = [i.id for i in obj_list[i].attachments.all()]if sortOrder == 'desc':no = total - (pageNumber - 1) * pageSize - ielse:no = (pageNumber - 1) * pageSize + i + 1row = {'id': obj_list[i].id,'no': no,'title': obj_list[i].title,'description': obj_list[i].description,'team': obj_list[i].team,'created_date': obj_list[i].created_date,'full_name': obj_list[i].full_name,'knowledge_category': obj_list[i].knowledge_category,'attachments': attachments,}rows.append(row)return data

下面附上前端分页的代码

{% extends "base.html" %} {% load static %}{% block main %}<style>.table th, .table td, .table b {text-align: center;vertical-align: middle !important;word-break: break-all;}</style><section class="section" id="da_kf"><div class="container"><div class="row justify-content-center"><div class="col-12 text-center"><div class="section-title mb-2"><h4 class="title mb-4">Key Features</h4><p class="text-muted para-desc mx-auto mb-0">Add some introduction here!</p></div></div><!--end col--></div><!--end row--><div class="row"><div class="col-lg-4 col-md-4 mt-4 pt-2"><div class="card features fea-primary rounded p-4 bg-light text-center position-relative overflow-hidden border-0"><span class="h1 icon2 text-primary"><a href="{% url 'stdfiles:download' 'HighRise Parameters & Values List' %}" class="text-reset">
{#                            <img src="{% static 'images/homepage/file-publisher.svg' %}" class="avatar avatar-md-sm"#}
{#                                 alt="">#}<i class="fas fa-stream"></i></a></span><div class="card-body p-0 content"><h6><a href="{% url 'stdfiles:download' 'HighRise Parameters & Values List' %}"class="text-reset">Highrise ParameterList</a></h6></div><span class="big-icon text-center"><i class="fas fa-stream"></i></span></div></div><!--end col--><div class="col-lg-4 col-md-4 mt-4 pt-2"><div class="card features fea-primary rounded p-4 bg-light text-center position-relative overflow-hidden border-0"><span class="h1 icon2 text-primary"><a href="{% url 'registers:comingsoon' %}" class="text-reset"><i class="fas fa-braille"></i></a></span><div class="card-body p-0 content"><h6><a href="{% url 'registers:comingsoon' %}" class="text-reset">Common Platform ParameterList</a></h6></div><span class="big-icon text-center"><i class="fas fa-braille"></i></span></div></div><!--end col--><div class="col-lg-4 col-md-4 mt-4 pt-2"><div class="card features fea-primary rounded p-4 bg-light text-center position-relative overflow-hidden border-0"><span class="h1 icon2 text-primary"><a href="{% url 'registers:comingsoon' %}" class="text-reset"><i class="fas fa-cogs"></i></a></span><div class="card-body p-0 content"><h6><a href="{% url 'registers:comingsoon' %}" class="text-reset">Other Features</a></h6></div><span class="big-icon text-center"><i class="fas fa-cogs"></i></span></div></div><!--end col--></div></div><!--end container--></section><!--end section--><!-- Key feature End --><!-- data structure index start --><section class="section  bg-light"><div class="container"><div class="row justify-content-center"><div class="col-12 text-center"><div class="section-title mb-4 pb-2"><h4 class="title mb-4">Data Structure List</h4></div></div><!--end col--></div><!--end row--><div id="toolbar"><div class="form-inline" role="form"><button id="remove" class="btn btn-soft-primary btn-sm"onclick="window.open('/teams/add_data_structure/')"><i class="fa fa-plus"></i> Add new data structure</button><!-- 自定义搜索查询 --><div class="input-group" style="left: 5px"><input id="search-keyword"class="form-control search-input" type="search"placeholder="Search" autocomplete="off"><div class="input-group-append"><button id="search-button" class="btn btn-soft-primary btn-sm" type="button" name="search"title="Search"><i class="fa fa-search"></i></button></div></div></div></div><!-- data structure index pagination --><table id="table"class="table-sm small"data-pagination="true"data-buttons-class="soft-primary btn-sm"data-sort-name="created_date"data-sort-order="desc"data-remember-order="true"data-show-fullscreen="true"data-show-columns="true"data-show-columns-toggle-all="true"data-show-export="true"data-click-to-select="true"data-toolbar="#toolbar"style="table-layout: fixed;height: auto"><thead class="thead-light"></table></div></section><!-- data structure index end --><!-- Team Members Start --><section class="section" id="da_team"><!-- Companies Start --><div class="container"><div class="row justify-content-center"><div class="col-12 text-center"><div class="section-title mb-2"><h4 class="title mb-4">Team Members</h4><p class="text-muted para-desc mx-auto mb-0">Add some introduction here!</p></div></div><!--end col--></div><!--end row--><div class="row"><div class="col-lg-4 col-md-6 col-12 mt-4 pt-2"><a href="page-job-detail.html"><div class="media key-feature align-items-center p-3 rounded shadow"><i class="fas fa-user-check"></i><div class="media-body ml-3"><h4 class="title mb-0 text-dark">Tian Xia</h4><p class="text-muted mb-0">Manager,....</p></div></div></a></div><!--end col--><div class="col-lg-4 col-md-6 col-12 mt-4 pt-2"><a href="page-job-detail.html"><div class="media key-feature align-items-center p-3 rounded shadow"><i class="fas fa-user-check"></i><div class="media-body ml-3"><h4 class="title mb-0 text-dark">Yang Fang</h4><p class="text-muted mb-0">Responsibility</p></div></div></a></div><!--end col--><div class="col-lg-4 col-md-6 col-12 mt-4 pt-2"><a href="page-job-detail.html"><div class="media key-feature align-items-center p-3 rounded shadow"><i class="fas fa-user-check"></i><div class="media-body ml-3"><h4 class="title mb-0 text-dark">Wang Xiaonan</h4><p class="text-muted mb-0">Responsibility</p></div></div></a></div><!--end col--><div class="col-lg-4 col-md-6 col-12 mt-4 pt-2"><a href="page-job-detail.html"><div class="media key-feature align-items-center p-3 rounded shadow"><i class="fas fa-user-check"></i><div class="media-body ml-3"><h4 class="title mb-0 text-dark">Ding Chenchen</h4><p class="text-muted mb-0">Responsibility</p></div></div></a></div><!--end col--></div><!--end row--></div><!--end container--><!-- Companies End --></section><!-- Team Members End -->
{% endblock %}{% block script %}<!-- JS for download table--><script>var $table = $('#table')$(function () {$('#toolbar').find('select').change(function () {$table.bootstrapTable('destroy').bootstrapTable({exportDataType: $(this).val(),exportTypes: ['excel', 'xml', 'csv', 'txt', 'sql'],columns: [{field: 'state',checkbox: true,visible: $(this).val() === 'selected'}]})}).trigger('change')})</script><!-- JS for pagination --><script>var $articlesTable = $('#table').bootstrapTable('destroy').bootstrapTable({url: '/teams/data_structure_list/',method: 'GET',dataType: "json",uniqueId: 'id',  //每一行的唯一标识,一般为主键列striped: false,  //是否显示行间隔色cache: false,sortName: 'no',sortable: true,sortOrder: 'desc',sidePagination: "server",undefinedText: '--',singleSelect: true,toolbar: '#toolbar',  //工具按钮用哪个容器showToggle: true,    //是否显示详细视图和列表视图的切换按钮strictSearch: true,clickToSelect: true,pagination: true,  //是否显示分页(*)showRefresh: true,  //是否显示刷新按钮pageNumber: 1,  //初始化加载第一页,默认第一页pageSize: 10,  //每页的记录行数(*)pageList: [10, 20, 50, 100, 'all'],paginationPreText: "<",paginationNextText: ">",queryParamsType: "",maxHeight: "200px",queryParams: function (params) {var query_params = {'pageSize': params.pageSize,'pageNumber': params.pageNumber,'search_kw': $('#search-keyword').val(), // 查询框中的参数传递给后台'sortName': params.sortName,'sortOrder': params.sortOrder};return query_params;},columns: [{field: 'no',title: 'No',align: 'center',halign: 'center',width: '60px',visible: true,sortable: true,formatter: function (value, row, index) {var result = "";result += '<a href="/teams/data_structure_detail/' + row.id + '/">' + row.no + '</a>'return result}},{field: 'id',title: 'DB_Id',align: 'center',halign: 'center',width: '70px',visible: false,sortable: true,formatter: function (value, row, index) {{#console.log(row)#}var result = "";result += '<a href="/teams/data_structure_detail/' + row.id + '/">' + row.id + '</a>'return result}},{field: 'title',title: 'title',align: 'left',halign: 'center',width: '180px',visible: true,formatter: function (value, row, index) {var result = "";result += '<a href="/teams/data_structure_detail/' + row.id + '/">' + row.title + '</a>'return result}},{field: 'description',title: 'Description',align: 'left',halign: 'center',width: '180px',visible: true,},{field: 'team',title: 'Team',align: 'left',halign: 'center',width: '100px',visible: true,},{field: 'knowledge_category',title: 'Knowledge Category',align: 'left',halign: 'center',width: '170px',visible: true,},{field: 'full_name',title: 'Owner',align: 'left',halign: 'center',width: '120px',visible: true,sortable: true,},{field: 'created_date',title: 'Upload date',align: 'center',halign: 'center',width: '120px',visible: true,sortable: true,},{field: 'attachments',title: 'Files',align: 'left',halign: 'center',width: '180px',visible: true,formatter: function (value, row, index) {var result = "";// 后台不使用序列化器{#for (var i = 0; i < row.attachments.id.length; i++) {result += '<a href="/file/teams_data_structure_file_download/' + row.attachments.id[i] + '">' + row.attachments.file_name[i] + ';<br/></a>'}#}// 后台使用序列化器for (var i = 0; i < row.attachments.length; i++) {result += '<a href="/file/teams_data_structure_file_download/' + row.attachments[i].id + '">' + row.attachments[i].file_name + ';<br/></a>'}return result}},{title: 'Operation',halign: 'center',width: '80px',visible: true,formatter: function (value, row, index) {var result = "";result += '<a href="/teams/data_structure_detail/' + row.id + '/" target="_blank"><i class="fas fa-edit"></i></a>&nbsp;&nbsp;&nbsp;'result += '<a href="#" οnclick="del_data_structure(' + row.id + ')"><i class="fas fa-trash-alt"></i></a>'return result}}],onLoadError: function (data) {console.log("数据加载失败!", "错误提示");$.messager.alert({title: '提示', msg: '数据加载失败!', icon: 'warning', top: 200});},});// 搜索查询按钮触发事件$("#search-button").click(function () {console.log($('#search-keyword').val())$('#table').bootstrapTable(('refresh'));})// 回车执行搜索$("#search-keyword").bind('keyup', function (event) {console.log($('#search-keyword').val())$('#table').bootstrapTable(('refresh'));})</script><!-- JS for delete data --><script>function del_data_structure(id) {console.log(id)$.messager.confirm({title: '提示', msg: '是否确认删除该条数据?', top: 200, fn: function (r) {if (r) {$.ajax({url: server_url + '/teams/data_structure_detail/' + id + '/',method: 'delete',processData: false,contentType: false,cache: false,success: function (data) {console.log("data:" + data);console.log("data:" + data.status);if (data.status === 200) {{#$.messager.alert({title: '提示', msg: data.msg, icon: 'warning', top: 200,});#}$.messager.show({title: '提示',msg: data.msg,showType: '',timeout: 500,style: {top: 200}});console.log("data:" + data.msg);$('#table').bootstrapTable('refresh');{#window.setTimeout("window.location=server_url+'/teams/data_structure/'", 600);#}return}console.log(data)$.messager.alert({title: '提示', msg: '权限不足或服务请求异常,数据无法删除!', icon: 'warning', top: 200});},//请求失败,包含具体的错误信息error: function (data) {console.log('error' + data.msg);$.messager.alert({title: '提示', msg: '请求服务错误或当前网络不佳!', icon: 'warning', top: 200});}});}}});}</script>
{% endblock %}

免声明:以上内容和代码仅供参考!


http://www.ppmy.cn/news/2041.html

相关文章

嵌入式开发--STM32硬件SPI驱动74HC595

本篇是硬件SPI口驱动74HC595。 IO口模拟时序软件驱动74HC595见这一篇文章&#xff1a;嵌入式开发–IO口扩展–74HC595 硬件连接如下&#xff1a; 只用了一个74HC595&#xff0c;如果需要多个74HC595级联&#xff0c;参考前面的链接&#xff0c;里面有电路&#xff0c;不需要额…

防火墙nat理论讲解

♥️作者&#xff1a;小刘在C站 ♥️每天分享云计算网络运维课堂笔记&#xff0c;疫情之下&#xff0c;你我素未谋面&#xff0c;但你一定要平平安安&#xff0c;一 起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的&#xff0c;绽放&#xff0c;愿…

Unity 动画系统(Animation,Animator,Timeline)

文章目录1. Animation1.1 创建Animation1.2 Animation 属性2. Animator2.1 Animator 组件2.2 Animation 状态2.3 状态控制参数2.4 代码中控制状态3. 代码控制动画的播放/暂停/继续播放1. Animation 1.1 创建Animation 选中需要添加动画的物体&#xff0c;打开Animation面板 …

ArgoDB 5.1 正式发布:多模融合、实时分析和数据安全多重升级

Transwarp ArgoDB是星环科技自主研发的高性能分布式分析型数据库&#xff0c;在PB级数据量上提供极致的数据分析能力。ArgoDB支持标准SQL语法和分布式事务&#xff0c;提供高并发高速数据写入、复杂查询、多模分析、数据联邦、隐私计算和动态脱敏等能力。基于星环科技ArgoDB数据…

Java高效率复习-MySQL上篇[MySQL]

前言 本文章是用于总结尚硅谷MySQL教学视频的记录文章&#xff0c;主要用于复习&#xff0c;非商用 原视频连接&#xff1a;https://www.bilibili.com/video/BV1iq4y1u7vj/?p21&spm_id_frompageDriver&vd_sourcec4ecde834521bad789baa9ee29af1f6c https://www.bilib…

[附源码]Python计算机毕业设计SSM教师职称资料管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

第七届 Sky Hackathon 笔记集合贴

Alex_McAvoy--------NVIDIA 7th SkyHackathon&#xff08;二&#xff09;开发套件的安装与测试 Alex_McAvoy--------NVIDIA 7th SkyHackathon&#xff08;三&#xff09;语音数据集的制作 Alex_McAvoy--------NVIDIA 7th SkyHackathon&#xff08;四&#xff09;Nemo ASR 模型训…

Android -- 每日一问:你在Android开发中遇到的技术难题是什么,你是怎么解决的?

经典回答 一个工作过几年的程序员肯定会有工作中遇到技术难点问题&#xff0c;虽然这个问题有可能对于别人不是技术难点&#xff0c;但只要对于当时的你是技术难点&#xff0c;只要让你抓耳挠腮毫无头绪就往往会在你的大脑中留下深刻的印象。 这个问题&#xff0c;我也比较难…