中文字幕人妻中文_99精品欧美一区二区三区综合在线_精品久久久久一区二区_色月丁香_免费福利在线视频_欧美大片免费观看网址_国产伦精品一区二区三区在线播放_污污污污污污www网站免费_久久月本道色综合久久_色69激情爱久久_尹人香蕉久久99天天拍_国产美女www_亚洲国产精品无码7777一线_五月婷婷六月激情_看免费一级片_精品久久久久久成人av_在线色亚洲_女人另类性混交zo_国产精品青青在线观看爽香蕉_人人澡人人添人人爽一区二区

主頁 > 知識庫 > 深度解析Django REST Framework 批量操作

深度解析Django REST Framework 批量操作

熱門標簽:哈爾濱ai外呼系統(tǒng)定制 海南400電話如何申請 公司電話機器人 白銀外呼系統(tǒng) 廣告地圖標注app 唐山智能外呼系統(tǒng)一般多少錢 騰訊外呼線路 激戰(zhàn)2地圖標注 陜西金融外呼系統(tǒng)

我們都知道Django rest framework這個庫,默認只支持批量查看,不支持批量更新(局部或整體)和批量刪除。

下面我們來討論這個問題,看看如何實現批量更新和刪除操作。

DRF基本情況

我們以下面的代碼作為例子:

models:

from django.db import models

# Create your models here.

class Classroom(models.Model):

    location = models.CharField(max_length=128)
    def __str__(self):
        return self.location


class Student(models.Model):
    name = models.CharField(max_length=32)
    classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

serializers:

from .models import Classroom, Student
from rest_framework.serializers import ModelSerializer

class StudentSerializer(ModelSerializer):

    class Meta:
        model = Student
        fields = "__all__"


class ClassroomSerializer(ModelSerializer):
    class Meta:
        model = Classroom
        fields = "__all__"

views:

from rest_framework.viewsets import ModelViewSet
from .serializers import StudentSerializer, ClassroomSerializer
from .models import Student, Classroom


class StudentViewSet(ModelViewSet):
    serializer_class = StudentSerializer
    queryset = Student.objects.all()


class ClassroomViewSet(ModelViewSet):
    serializer_class = ClassroomSerializer
    queryset = Classroom.objects.all()

myapp/urls:

from rest_framework.routers import DefaultRouter
from .views import StudentViewSet, ClassroomViewSet

router = DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'classrooms', ClassroomViewSet)

urlpatterns = router.urls

根urls:

from django.contrib import admin
from django.urls import path,include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('myapp.urls')),
]

這是一個相當簡單而又經典的場景。其中的Classroom模型不是重點,只是為了豐富元素,展示一般場景。

創(chuàng)建數據:

  • 通過post方法訪問127.0.0.1:8000/classrooms/創(chuàng)建一些教室數據。
  • 通過post方法訪問127.0.0.1:8000/students/創(chuàng)建一些學生數據。



可以很清楚地看到DRF默認:

  • 通過GET /students/查看所有的學生
  • 通過GET /students/1/查看id為1的學生
  • 通過POST /students/攜帶一個數據字典,創(chuàng)建單個學生
  • 通過PUT/students/1/整體更新id為1的學生信息
  • 通過PATCH /students/1/局部更新id為1的學生信息
  • 通過DELETE/students/1/刪除id為1的學生

沒有批量更新和刪除的接口。

并且當我們嘗試向/students/,POST一個攜帶了多個數據字典的列表對象時,比如下面的數據:

[
    {
        "name": "alex",
        "classroom": 1
    },
    {
        "name": "mary",
        "classroom": 2
    },
    {
        "name": "kk",
        "classroom": 3
    }
]

反饋給我們的如下圖所示:

錯誤提示:非法的數據,期望一個字典,但你提供了一個列表。

至于嘗試向更新和刪除接口提供多個對象的id,同樣無法操作。

可見在DRF中,默認情況下,只能批量查看,不能批量創(chuàng)建、修改和刪除。

自定義批量操作

現實中,難免有批量的創(chuàng)建、修改和刪除需求。那怎么辦呢?只能自己寫代碼實現了。

下面是初學者隨便寫的代碼,未考慮數據合法性、安全性、可擴展性等等,僅僅是最基礎的實現了功能而已:

批量創(chuàng)建

class StudentViewSet(ModelViewSet):
    serializer_class = StudentSerializer
    queryset = Student.objects.all()

    # 通過many=True直接改造原有的API,使其可以批量創(chuàng)建
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs.setdefault('context', self.get_serializer_context())
        if isinstance(self.request.data, list):
            return serializer_class(many=True, *args, **kwargs)
        else:
            return serializer_class(*args, **kwargs)

DRF本身提供了一個ListSerializer,這個類是實現批量創(chuàng)建的核心關鍵。

當我們在實例化一個序列化器的時候,有一個關鍵字參數many,如果將它設置為True,就表示我們要進行批量操作,DRF在后臺會自動使用ListSerializer來替代默認的Serializer。

所以,實現批量創(chuàng)建的核心就是如何將many參數添加進去。

這里,我們重寫了get_serializer方法,通過if isinstance(self.request.data, list):語句,分析前端發(fā)送過來的數據到底是個字典還是個列表。如果是個字典,表示這是創(chuàng)建單個對象,如果是個列表,表示是創(chuàng)建批量對象。

讓我們測試一下。首先,依然可以正常地創(chuàng)建單個對象。

然后如下面的方式,通過POST 往/students/發(fā)送一個列表:

這里有個坑,可能會碰到AttributeError: 'ListSerializer' object has no attribute 'fields'錯誤。

這是響應數據格式的問題。沒關系。刷新頁面即可。

也可以在POSTMAN中進行測試,就不會出現這個問題。

批量刪除

先上代碼:

from rest_framework.viewsets import ModelViewSet
from .serializers import StudentSerializer, ClassroomSerializer
from .models import Student, Classroom
from rest_framework import status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from rest_framework.decorators import action



class StudentViewSet(ModelViewSet):
    serializer_class = StudentSerializer
    queryset = Student.objects.all()

    # 通過many=True直接改造原有的API,使其可以批量創(chuàng)建
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs.setdefault('context', self.get_serializer_context())
        if isinstance(self.request.data, list):
            return serializer_class(many=True, *args, **kwargs)
        else:
            return serializer_class(*args, **kwargs)

    # 新增一個批量刪除的API。刪除單個對象,依然建議使用原API
    # 通過DELETE訪問訪問url domain.com/students/multiple_delete/?pks=4,5
    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        # 獲取要刪除的對象們的主鍵值
        pks = request.query_params.get('pks', None)
        if not pks:
            return Response(status=status.HTTP_404_NOT_FOUND)
        for pk in pks.split(','):
            get_object_or_404(Student, id=int(pk)).delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

要注意,原DRF是通過DELETE/students/1/刪除id為1的學生。

那么如果我想批量刪除id為1,3,5的三個數據怎么辦?

反正肯定是不能往/students/1/這樣的url發(fā)送請求的。

那么是構造一條這樣的url嗎?/students/1,3,5/?或者/students/?pk=1,3,5

還是往/students/發(fā)送json數據[1,3,5]?

這里,我采用/students/multiple_delete/?pks=1,3,5的形式。

這樣,它創(chuàng)建了一條新的接口,既避開了/students/這個接口,也能通過url發(fā)送參數。

由于我們的視圖繼承的是ModelViewSet,所以需要通過action裝飾器,增加一個同名的multiple_delete()方法。

為了防止id和Python內置的id函數沖突。我們這里使用pks作為url的參數名。

通過一個for循環(huán),分割逗號獲取批量主鍵值。

通過主鍵值去數據庫中查找對象,然后刪除。(這里只是實現功能,未處理異常)

下面,最好在POSTMAN中測試一下:

注意請求是DELETE /students/multiple_delete/?pks=4,5

再訪問/students/,可以看到相關數據確實被刪除了。

批量更新

代碼如下:

from rest_framework.viewsets import ModelViewSet
from .serializers import StudentSerializer, ClassroomSerializer
from .models import Student, Classroom
from rest_framework import status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from rest_framework.decorators import action



class StudentViewSet(ModelViewSet):
    serializer_class = StudentSerializer
    queryset = Student.objects.all()

    # 通過many=True直接改造原有的API,使其可以批量創(chuàng)建
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs.setdefault('context', self.get_serializer_context())
        if isinstance(self.request.data, list):
            return serializer_class(many=True, *args, **kwargs)
        else:
            return serializer_class(*args, **kwargs)

    # 新增一個批量刪除的API。刪除單個對象,依然建議使用原API
    # 通過DELETE訪問訪問url domain.com/students/multiple_delete/?pks=4,5
    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        pks = request.query_params.get('pks', None)
        if not pks:
            return Response(status=status.HTTP_404_NOT_FOUND)
        for pk in pks.split(','):
            get_object_or_404(Student, id=int(pk)).delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    # 新增一個批量修改的API。更新單個對象,依然建議使用原API
    # 通過PUT方法訪問url domain.com/students/multiple_update/
    # 發(fā)送json格式的數據,數據是個列表,列表中的每一項是個字典,每個字典是一個實例
    @action(methods=['put'], detail=False)
    def multiple_update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instances = []  # 這個變量是用于保存修改過后的對象,返回給前端
        for item in request.data:  # 遍歷列表中的每個對象字典
            instance = get_object_or_404(Student, id=int(item['id']))  # 通過ORM查找實例
            # 構造序列化對象,注意partial=True表示允許局部更新
            # 由于我們前面重寫了get_serializer方法,進行了many=True的判斷。
            # 但此處不需要many=True的判斷,所以必須調用父類的get_serializer方法
            serializer = super().get_serializer(instance, data=item, partial=partial)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            instances.append(serializer.data)  # 將數據添加到列表中
        return Response(instances)

更新和刪除不同的地方在于,它在提供主鍵值的同時,還需要提供新的字段值。

所以,這里我們將主鍵值放在json數據中,而不是作為url的參數。

請仔細閱讀上面的代碼注釋。

這里有個小技巧,其實可以根據HTTP的PUT和PATCH的不同,靈活設定partial參數的值。

另外,要注意的對get_serializer()方法的處理。

下面測試一下。在POSTMAN中通過PUT方法,訪問/students/multiple_update/,并攜帶如下的json數據:

[
    {
        "id":2,
    	"name":"tom",
    	"classroom":3
    },
    {
        "id":3,
        "name":"jack",
        "classroom":2
    }
]

上面是整體更新,局部更新也是可以的。

djangorestframework-bulk

前面,我們通過蹩腳的代碼,實現了最基礎的批量增刪改查。

但問題太多,不夠優(yōu)雅清晰、異常未處理、邊界未考慮等等,實在是太爛。

事實上,有這么個djangorestframework-bulk庫,已經高水平地實現了我們的需求。

這個庫非常簡單,核心的其實只有3個模塊,核心代碼也就300行左右,非常短小精干,建議精讀它的源碼,肯定會有收獲。

官網:https://pypi.org/project/djangorestframework-bulk/

github:https://github.com/miki725/django-rest-framework-bulk

最后更新:2015年4月

最后版本:0.2.1

它有兩個序列化器的版本:drf2\drf3。我們用drf3。

依賴

  • Python > = 2.7
  • 的Django > = 1.3
  • Django REST framework > = 3.0.0

安裝

使用pip:

$ pip install djangorestframework-bulk

范例

視圖

我們注釋掉前面章節(jié)中的代碼,編寫下面的代碼,使用bulk庫來實現批量操作。

bulk中的views(和mixins)非常類似drf原生的generic views(和mixins)

from rest_framework.serializers import ModelSerializer
from .models import Student
from rest_framework_bulk import (
    BulkListSerializer,
    BulkSerializerMixin,
    BulkModelViewSet
)
from rest_framework.filters import SearchFilter

# 序列化器。暫時寫在視圖模塊里
# 必須先繼承BulkSerializerMixin,由它將只讀字段id的值寫回到validated_data中,才能實現更新操作。
class StudentSerializer(BulkSerializerMixin, ModelSerializer):
    class Meta(object):
        model = Student
        fields = '__all__'
        
        # 在Meta類下面的list_serializer_class選項用來修改當`many=True`時使用的類。
        # 默認情況下,DRF使用的是ListSerializer。
        # 但是ListSerializer沒有實現自己的批量update方法。
        # 在DRF3中如果需要批量更新對象,則需定義此屬性,并編寫ListSerializer的子類
        # 所以bulk庫提供了一個BulkListSerializer類
        # 它直接繼承了ListSerializer,并重寫了update方法。
        list_serializer_class = BulkListSerializer
        
        # 這條可以不寫。但實際上,批量刪除需要搭配過濾操作
        filter_backends = (SearchFilter,) 

# 視圖集
class StudentView(BulkModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    def allow_bulk_destroy(self, qs, filtered):
        # 這里作為例子,簡單粗暴地直接允許批量刪除
        return True

然后我們將自動獲得下面的功能:

# 批量查詢
GET    http://127.0.0.1/students/


# 創(chuàng)建單個對象
POST  	http://127.0.0.1/students/
body   {"field":"value","field2":"value2"}    發(fā)送字典格式的json數據


# 創(chuàng)建多個對象
POST 	http://127.0.0.1/students/
body	[{"field":"value","field2":"value2"}]   發(fā)送列表格式的json數據


# 更新多個對象(需要提供所有字段的值)
PUT 	http://127.0.0.1/students/
body	[{"field":"value","field2":"value2"}]   發(fā)送列表格式的json數據


# 局部更新多個對象(不需要提供所有字段的值)
PATCH 	http://127.0.0.1/students/
body 	[{"field":"value"}]                     發(fā)送列表格式的json數據


# 刪除多個對象
DELETE   http://127.0.0.1/students/

當然,原生的單個對象的操作也是依然支持的!

要特別注意DELETE操作,這個例子里會直接將所有的數據全部刪除。如果你想刪除指定的一批數據,可以搭配filter_backends來過濾查詢集,使用allow_bulk_destroy方法來自定義刪除策略。

可以看到bulk庫對于RESTful的url沒有任何改動,非常優(yōu)雅,比我們上面的蹩腳方法強太多。

路由

路由也需要修改一下。

bulk的路由可以自動映射批量操作,它對DRF原生的DefaultRouter進行了簡單的封裝:

from rest_framework_bulk.routes import BulkRouter
from .views import StudentView

router = BulkRouter()
router.register(r'students', StudentView)

urlpatterns = router.urls

測試

現在可以測試一下。下面提供一部分測試數據:

[
    {
        "name": "s1",
        "classroom": 1
    },
    {
        "name": "s2",
        "classroom": 3
    },
    {
        "name": "s3",
        "classroom": 2
    }
]
  • 建議在POSTMAN中進行測試
  • PUT和PATCH要攜帶id值
  • PUT要攜帶所有字段的值
  • PATCH可以只攜帶要更新的字段的值
  • DELETE一定要小心

可以看到功能完全實現,批量操作成功。

DRF3相關

DRF3的API相比DRF2具有很多變化,尤其是在序列化器上。要在DRF3上使用bulk,需要注意以下幾點:

如果你的視圖需要批量更新功能,則必須指定 list_serializer_class (也就是繼承了 BulkUpdateModelMixin時)

DRF3 從 serializer.validated_data中移除了只讀字段。所以,無法關聯(lián) validated_dataListSerializer ,因為缺少模型主鍵這個只讀字段。為了解決這個問題,你必須在你的序列化類中使用 BulkSerializerMixin ,這個混入類會添加模型主鍵字段到 validated_data中。默認情況,模型主鍵是 id ,你可以通過 update_lookup_field 屬性來指定主鍵名:

class FooSerializer(BulkSerializerMixin, ModelSerializer):
    class Meta(object):
        model = FooModel
        list_serializer_class = BulkListSerializer
        update_lookup_field = 'slug'

注意事項

大多數API的每種資源都有兩個級別的url:

  • url(r'foo/', ...)
  • url(r'foo/(?Ppk>\d+)/', ...)

但是,第二個URL不適用于批量操作,因為該URL直接映射到單個資源。因此,所有批量通用視圖僅適用于第一個URL。

如果只需要某個單獨的批量操作功能,bulk提供了多個通用視圖類。例如,ListBulkCreateAPIView 將僅執(zhí)行批量創(chuàng)建操作。有關可用的通用視圖類的完整列表,請訪問generics.py的源代碼。

大多數批量操作都是安全的,因為數據都是和每個對象關聯(lián)的。例如,如果您需要更新3個特定資源,則必須在PUTPATCH的請求數據中明確的標識出那些資源的id。唯一的例外是批量刪除,例如對第一種URL的DELETE請求可能會刪除所有資源,而無需任何特殊確認。為了解決這個問題,批量刪除混入類中提供了一個鉤子,以確定是否應允許執(zhí)行該批量刪除請求,也就是allow_bulk_destroy方法:

class FooView(BulkDestroyAPIView):
    def allow_bulk_destroy(self, qs, filtered):
        # 你的自定義業(yè)務邏輯寫在這里

        # qs參數是一個查詢集,它來自self.get_queryset()
        # 默認要檢查qs是否被過濾了。
        # filtered參數來自self.filter_queryset(qs)
        return qs is not filtered   # 最終返回True,則執(zhí)行刪除操作。返回False,則不執(zhí)行。

默認情況下,allow_bulk_destroy方法會檢查查詢集是否已過濾,如果沒有過濾,則不允許執(zhí)行該批量刪除操作。此處的邏輯是,你知道自己在刪除哪些對象,知道自己沒有進行全部對象的刪除操作。通俗地說就是,程序員對你的代碼在作什么,心里要有數。

源碼解讀

下圖是目錄組織結構。分drf2和drf3,基本使用drf3。test目錄我們不關心。

核心其實就是根目錄下的5個模塊和drf3目錄。其中的models.py文件是空的,沒有代碼。

__init__.py

這個模塊就是簡單地導入其它模塊:

__version__ = '0.2.1'
__author__ = 'Miroslav Shubernetskiy'

try:
    from .generics import *  # noqa
    from .mixins import *  # noqa
    from .serializers import *  # noqa
except Exception:
    pass

#NOQA 注釋的作用是告訴PEP8規(guī)范檢測工具,這個地方不需要檢測。

也可以在一個文件的第一行增加 #flake8:NOQA 來告訴規(guī)范檢測工具,這個文件不用檢查。

serializers.py

源代碼:

# 這是用于Python版本兼容,print方法和Unicode字符
from __future__ import print_function, unicode_literals
import rest_framework

if str(rest_framework.__version__).startswith('2'):
    from .drf2.serializers import *  # noqa
else:
    from .drf3.serializers import *  # noqa

就是針對不同的DRF版本,導入不同的serializers。

mixins.py

源代碼:

from __future__ import print_function, unicode_literals
import rest_framework

if str(rest_framework.__version__).startswith('2'):
    from .drf2.mixins import *  # noqa
else:
    from .drf3.mixins import *  # noqa

和serializers.py類似,針對不同的DRF版本,導入不同的mixins。

routes.py

搭配bulk的BulkModelViewSet視圖類進行工作。

源代碼:

from __future__ import unicode_literals, print_function
import copy
from rest_framework.routers import DefaultRouter, SimpleRouter


__all__ = [
    'BulkRouter',
]


class BulkRouter(DefaultRouter):
    """
    將http的method映射到bulk的minxins中的處理函數
    """
    routes = copy.deepcopy(SimpleRouter.routes)
    routes[0].mapping.update({
        'put': 'bulk_update',
        'patch': 'partial_bulk_update',
        'delete': 'bulk_destroy',
    })

對DRF原生的DefaultRouter路由模塊進行再次封裝,主要是修改三個HTTP方法的映射關系,將它們映射到bulk庫的mixins方法。

generics.py

這個模塊的風格和DRF的源碼非常類似,都是各種繼承搭配出來各種類視圖。

里面混用了DRF原生的mixin和bulk自己寫的mixin。

主要是將http的method映射到視圖類中對應的處理方法。

源代碼:

from __future__ import unicode_literals, print_function
from rest_framework import mixins
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import ModelViewSet

from . import mixins as bulk_mixins


__all__ = [
    'BulkCreateAPIView',
    'BulkDestroyAPIView',
    'BulkModelViewSet',
    'BulkUpdateAPIView',
    'ListBulkCreateAPIView',
    'ListBulkCreateDestroyAPIView',
    'ListBulkCreateUpdateAPIView',
    'ListBulkCreateUpdateDestroyAPIView',
    'ListCreateBulkUpdateAPIView',
    'ListCreateBulkUpdateDestroyAPIView',
]


# ################################################## #
# 下面是一些具體的視圖類。通過將mixin類與基視圖組合來提供方法處理程序。
# 基本前面繼承一堆mixins,后面繼承GenericAPIView
# ################################################## #

# 批量創(chuàng)建
class BulkCreateAPIView(bulk_mixins.BulkCreateModelMixin,
                        GenericAPIView):
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

# 批量更新(局部和整體)
class BulkUpdateAPIView(bulk_mixins.BulkUpdateModelMixin,
                        GenericAPIView):
    def put(self, request, *args, **kwargs):
        return self.bulk_update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_bulk_update(request, *args, **kwargs)

# 批量刪除
class BulkDestroyAPIView(bulk_mixins.BulkDestroyModelMixin,
                         GenericAPIView):
    def delete(self, request, *args, **kwargs):
        return self.bulk_destroy(request, *args, **kwargs)

# 批量查看和創(chuàng)建
# 注意批量查看依然使用的是DRF原生的ListModelMixin提供的功能
class ListBulkCreateAPIView(mixins.ListModelMixin,
                            bulk_mixins.BulkCreateModelMixin,
                            GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

# 批量查看、單個創(chuàng)建、批量更新
class ListCreateBulkUpdateAPIView(mixins.ListModelMixin,
                                  mixins.CreateModelMixin,
                                  bulk_mixins.BulkUpdateModelMixin,
                                  GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.bulk_update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_bulk_update(request, *args, **kwargs)


class ListCreateBulkUpdateDestroyAPIView(mixins.ListModelMixin,
                                         mixins.CreateModelMixin,
                                         bulk_mixins.BulkUpdateModelMixin,
                                         bulk_mixins.BulkDestroyModelMixin,
                                         GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.bulk_update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_bulk_update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.bulk_destroy(request, *args, **kwargs)


class ListBulkCreateUpdateAPIView(mixins.ListModelMixin,
                                  bulk_mixins.BulkCreateModelMixin,
                                  bulk_mixins.BulkUpdateModelMixin,
                                  GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.bulk_update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_bulk_update(request, *args, **kwargs)


class ListBulkCreateDestroyAPIView(mixins.ListModelMixin,
                                   bulk_mixins.BulkCreateModelMixin,
                                   bulk_mixins.BulkDestroyModelMixin,
                                   GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.bulk_destroy(request, *args, **kwargs)

# 這個功能最全面
class ListBulkCreateUpdateDestroyAPIView(mixins.ListModelMixin,
                                         bulk_mixins.BulkCreateModelMixin,
                                         bulk_mixins.BulkUpdateModelMixin,
                                         bulk_mixins.BulkDestroyModelMixin,
                                         GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.bulk_update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_bulk_update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.bulk_destroy(request, *args, **kwargs)


# ########################################################## #
# 專門提供的一個viewset,搭配了批量創(chuàng)建、更新和刪除功能
# 它需要搭配bulk的router模塊使用。
# 如果不用這個,就用ListBulkCreateUpdateDestroyAPIView
# ########################################################## #

class BulkModelViewSet(bulk_mixins.BulkCreateModelMixin,
                       bulk_mixins.BulkUpdateModelMixin,
                       bulk_mixins.BulkDestroyModelMixin,
                       ModelViewSet):
    pass

drf3/mixins.py

這個模塊實現了核心的業(yè)務邏輯。請注意閱讀源代碼中的注釋。

源代碼:

from __future__ import print_function, unicode_literals
from rest_framework import status
from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response


__all__ = [
    'BulkCreateModelMixin',
    'BulkDestroyModelMixin',
    'BulkUpdateModelMixin',
]


class BulkCreateModelMixin(CreateModelMixin):
    """
    Django REST >= 2.2.5.以后的版本多了一個many=True的參數。
    通過這個參數,可以實現單個和批量創(chuàng)建實例的統(tǒng)一操作。
    其本質是使用DRF提供的ListSerializer類
    """
	# 重寫create方法
    def create(self, request, *args, **kwargs):
        # 通過判斷request.data變量是列表還是字典,來區(qū)分是單體操作還是批量操作。
        # 這要求我們前端發(fā)送json格式的數據時,必須定義好數據格式
        bulk = isinstance(request.data, list)

        if not bulk: # 如果不是批量操作,則調用父類的單體創(chuàng)建方法
            return super(BulkCreateModelMixin, self).create(request, *args, **kwargs)

        else:  # 如果是批量操作,則添加many=True參數
            serializer = self.get_serializer(data=request.data, many=True)
            serializer.is_valid(raise_exception=True)
            # 這里少了DRF源碼中的headers = self.get_success_headers(serializer.data)         
            self.perform_bulk_create(serializer)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
	# 這是個鉤子方法
    def perform_bulk_create(self, serializer):
        return self.perform_create(serializer)


class BulkUpdateModelMixin(object):
    """
	同樣是通過many=True參數來實現批量更新
    """
	# 重寫單個對象的獲取
    def get_object(self):
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
		# 這個if執(zhí)行的是父類的操作
        if lookup_url_kwarg in self.kwargs:
            return super(BulkUpdateModelMixin, self).get_object()
		# 如果沒有攜帶id,則直接返回,什么都不做。
        # 也就是  PUT 	http://127.0.0.1/students/
        # 和	    PUT	 http://127.0.0.1/students/1/的區(qū)別
        return
	
    # 核心的更新方法
    def bulk_update(self, request, *args, **kwargs):
        # 先看看是PUT還是PATCH
        partial = kwargs.pop('partial', False)

        # 限制只對過濾后的查詢集進行更新
        # 下面的代碼就是基本的DRF反序列化套路
        # 核心是instances是個過濾集,many指定為True,partial根據方法來變
        # 這里的邏輯是將單體更新當作只有一個元素的列表來更新(也就是批量為1)。
        serializer = self.get_serializer(
            self.filter_queryset(self.get_queryset()),
            data=request.data,
            many=True,
            partial=partial,
        )
        serializer.is_valid(raise_exception=True)
        self.perform_bulk_update(serializer)
        return Response(serializer.data, status=status.HTTP_200_OK)
	
    # 如果是PATCH方法,則手動添加partial=True參數,表示局部更新
    # 實際執(zhí)行的方法和整體更新一樣,都是調用bulk_update方法
    def partial_bulk_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.bulk_update(request, *args, **kwargs)
	
    # 鉤子方法
    def perform_update(self, serializer):
        serializer.save()
	# 鉤子方法
    def perform_bulk_update(self, serializer):
        return self.perform_update(serializer)


# 刪除操作
class BulkDestroyModelMixin(object):
    """
    用于刪除模型實例
    """

    def allow_bulk_destroy(self, qs, filtered):
        """
        這是一個鉤子,用于確保批量刪除操作是安全的。
        默認情況下,它會檢查刪除操作是否在一個過濾集上進行,不能對原始查詢集也就是qs進行刪除。
		最終的返回值是布爾值,如果返回True,表示允許刪除,否則拒絕。
		源碼這里是簡單地比較了qs和filtered是否相同,你可以自定義判斷邏輯。
		刪除操作可以配合過濾后端。
        """
        return qs is not filtered
	# DELETE方法將被轉發(fā)到這里
    def bulk_destroy(self, request, *args, **kwargs):
        # 首先,獲取查詢集
        qs = self.get_queryset()
		# 獲取過濾集
        filtered = self.filter_queryset(qs)
        # 調用allow_bulk_destroy方法,判斷是否允許該刪除操作
        if not self.allow_bulk_destroy(qs, filtered):
            # 如果不允許,返回400響應,錯誤的請求
            return Response(status=status.HTTP_400_BAD_REQUEST)
		# 否則對過濾集執(zhí)行批量刪除操作
        self.perform_bulk_destroy(filtered)

        return Response(status=status.HTTP_204_NO_CONTENT)
	
    # 這個刪除方法,其實就是ORM的delete方法
    # 之所以設置這個方法,其實就是個鉤子,方便我們自定義
    def perform_destroy(self, instance):
        instance.delete()
	
    # 批量刪除很簡單,就是遍歷過濾集,逐個刪除
    def perform_bulk_destroy(self, objects):
        for obj in objects:
            self.perform_destroy(obj)

drf3/serializers.py

這個模塊只有兩個類,它們提供了2個功能。

  • BulkSerializerMixin:往驗證后的數據中添加主鍵字段的值
  • BulkListSerializer:提供批量更新的update方法

源代碼:

from __future__ import print_function, unicode_literals
import inspect  # Python內置模塊。從活動的Python對象獲取有用的信息。

from rest_framework.exceptions import ValidationError
from rest_framework.serializers import ListSerializer


__all__ = [
    'BulkListSerializer',
    'BulkSerializerMixin',
]

# 由于DRF源碼在默認情況下,會將只讀字段的值去掉,所以id主鍵值不會出現在validated_data中
# 因為我們現在需要批量更新對象,url中也沒有攜帶對象的id,所以我們需要手動將id的值添加回去。
class BulkSerializerMixin(object):
    # 由外部數據轉換為Python內部字典
    def to_internal_value(self, data):
        # 先調用父類的方法,獲得返回值
        ret = super(BulkSerializerMixin, self).to_internal_value(data)
		# 去Meta元類中看看,有沒有指定'update_lookup_field'屬性,如果沒有,默認使用id
        # 這本質就是個鉤子,允許我們自定義主鍵字段
        id_attr = getattr(self.Meta, 'update_lookup_field', 'id')
        # 獲取當前請求的類型
        request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '')
		
        # 如果下面的三個條件都滿足:
        # self.root是BulkListSerializer的實例
        # id_attr變量不為空
        # 請求的方法是'PUT'或'PATCH'
        # 那么執(zhí)行if語句中的代碼
        if all((isinstance(self.root, BulkListSerializer),
                id_attr,
                request_method in ('PUT', 'PATCH'))):
            # 拿到id字段的句柄
            id_field = self.fields[id_attr]
            # 拿到字段的值	
            id_value = id_field.get_value(data)
			# 為ret追加鍵值對
            ret[id_attr] = id_value

        return ret

# 這個類主要是在ListSerializer基礎上重寫的update邏輯,實現批量操作
class BulkListSerializer(ListSerializer):
    # 指定用于更新的查詢字段為id
    update_lookup_field = 'id'

    def update(self, queryset, all_validated_data):
        # 先看看有沒有指定用于查詢的字段
        id_attr = getattr(self.child.Meta, 'update_lookup_field', 'id')
		# 通過id去獲取所有的鍵值對
        # 下面是一個字典推導式
        all_validated_data_by_id = {
            i.pop(id_attr): i
            for i in all_validated_data
        }
		# 對數據類型做判斷
        if not all((bool(i) and not inspect.isclass(i)
                    for i in all_validated_data_by_id.keys())):
            raise ValidationError('')


        # 使用ORM從查詢集中過濾出那些需要更新的模型實例
        # 比如id__in=[1,3,4]
        objects_to_update = queryset.filter(**{
            '{}__in'.format(id_attr): all_validated_data_by_id.keys(),
        })
		# 如果過濾出來的模型實例數量和用于更新的數據數量不一致,彈出異常
        if len(all_validated_data_by_id) != objects_to_update.count():
            raise ValidationError('Could not find all objects to update.')
		# 準備一個空列表,用于保存將要被更新的實例
        updated_objects = []
		# 循環(huán)每個實例
        for obj in objects_to_update:
            obj_id = getattr(obj, id_attr)
            obj_validated_data = all_validated_data_by_id.get(obj_id)
            # 使用模型序列化器的update方法進行實際的更新動作,以防update方法在別的地方被覆蓋
            updated_objects.append(self.child.update(obj, obj_validated_data))

        return updated_objects

到此這篇關于深度解析Django REST Framework 批量操作的文章就介紹到這了,更多相關Django REST Framework批量操作內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Django Rest framework之認證的實現代碼
  • Django Rest framework認證組件詳細用法
  • python django 實現驗證碼的功能實例代碼
  • django rest framework 實現用戶登錄認證詳解
  • Python編程使用DRF實現一次性驗證碼OTP

標簽:鷹潭 惠州 黔西 上海 黑龍江 四川 常德 益陽

巨人網絡通訊聲明:本文標題《深度解析Django REST Framework 批量操作》,本文關鍵詞  深度,解析,Django,REST,Framework,;如發(fā)現本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統(tǒng)采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《深度解析Django REST Framework 批量操作》相關的同類信息!
  • 本頁收集關于深度解析Django REST Framework 批量操作的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 湖南嘉龙机械设备贸易有限公司| 东莞机械设备制造有限公司| 张家港机械设备有限公司| 海宁诚达机械有限公司| 五莲县机械有限公司| 安阳锻压机械有限公司| 上海山威路桥机械有限公司| 天工工程机械有限公司| 常州拓美威精密机械有限公司| 河南天成矿山起重机有限公司 | 青岛大牧人机械有限公司| 佛山市信虹精密机械有限公司| 威海汇鑫化工机械有限公司| 穗华机械设备有限公司| 上海澳昊机械制造有限公司| 上海启秀机械设备有限公司| 临工工程机械有限公司| 山东金奥机械有限公司| 昆山市机械制造有限公司| 江苏隆达机械设备有限公司| 亚德林机械有限公司| 蚌埠 机械有限公司| 首钢长治钢铁有限公司| 苏州久富农业机械有限公司| 五莲县机械有限公司| 浙江邦泰机械有限公司| 昆山精密机械有限公司| 重庆华世丹机械制造有限公司| 青岛威尔塑料机械有限公司| 上海诚淘机械有限公司| 江阴万恒机械制造有限公司| 昆山尚亦精密机械有限公司| 上海霏润机械设备有限公司| 浙江瑞德森机械有限公司| 东营海河机械有限公司| 南通凯迪自动机械有限公司| 苏州松发机械有限公司| 粮油机械设备有限公司| 丹东富田精工机械有限公司| 沈阳韩兆机械有限公司| 天重江天重工有限公司| 固达机械制造有限公司| 纽科伦新乡起重机有限公司| 青岛 木工机械有限公司| 上海 马机械有限公司| 台州 精密机械有限公司| 新昌县机械有限公司| 广州起航贸易有限公司| 重庆鹏程钢铁有限公司| 常州经编机械有限公司| 矿山机械设备有限公司| 苏州信能精密机械有限公司| 常州武进机械有限公司| 邢台凌远机械制造有限公司| 成都蓉诚机械设备有限公司| 浙江万宝机械有限公司| 玉环双友机械有限公司| 广东三浦重工有限公司| 广西中源机械有限公司| 新世纪机械有限公司| 常州纺织机械有限公司| 杭州亿安机械设备有限公司| 中山冠力机械有限公司| 鸡西煤矿机械有限公司| 衡阳运输机械有限公司| 东莞市嘉鲁特注塑机械有限公司| 长沙昊博机械设备有限公司| 宁波星源机械有限公司| 宁波信泰机械有限公司| 申耀机械工业有限公司| 哈挺精密机械有限公司| 山西立恒钢铁有限公司| 河南世茂机械制造有限公司| 佛山市创利宝包装机械有限公司 | 柳州市宏华机械有限公司| 章丘宇龙机械有限公司| 苏州松博机械有限公司| 无锡纺织机械有限公司| 江苏久保田农机机械有限公司| 东莞市顺翼机械有限公司| 广州力丰机械有限公司| 机械有限公司怎么注册| 徐工基础工程机械有限公司| 东莞机械设备有限公司| 建湖液压机械有限公司| 新乡市欧霖佳机械有限公司| 昆山烽禾升精密机械有限公司| 东莞志成机械有限公司| 无锡化工机械有限公司| 苏州典艺精密机械有限公司| 鸡西煤矿机械有限公司| 重型机械制造有限公司| 浙江坤鸿机械设备有限公司| 中机北方机械有限公司| 涂装机械设备有限公司| 安宁市永昌钢铁有限公司| 南通航力重工机械有限公司| 盐山宏润重工有限公司| 浙江华业塑料机械有限公司| 山西 重工有限公司| 重庆舰帏机械有限公司| 河北华西钢铁有限公司| 常州 机械制造有限公司| 济南天助升降机械有限公司| 南京高立工程机械有限公司| 安丰钢铁有限公司地址| 重庆箭驰机械有限公司| 贵州工程机械有限公司| 天津华悦包装机械有限公司| 农业机械有限公司招聘| 莱州市鲁樽机械有限公司| 曲阜机械设备有限公司| 河北卓昊机械制造有限公司| 杭重工程机械有限公司| 宝鸡 机械有限公司| 合肥至信机械有限公司| 无锡金球机械有限公司| 深圳格瑞克机械有限公司| 太仓鸿安机械有限公司| 东宇机械设备有限公司| 宁波康博机械有限公司| 哈尔滨机械有限公司| 东莞市巨冈机械工业有限公司| 宁波伟隆传动机械有限公司 | 上海海韬机械有限公司| 昆明远桥机械有限公司| 范斯特机械有限公司| 机械维修 有限公司| 安徽鸿泰钢铁有限公司| 江南起重机械有限公司| 江苏洪流化工机械有限公司 | 余姚市机械有限公司| 邦贝液压机械有限公司| 扬州液压机械有限公司| 仕诚塑料机械有限公司| 运输有限公司起名大全| 潍坊精诺机械有限公司| 菲美得机械有限公司| 河南宝润机械有限公司| 上海瑞派机械有限公司招聘| 天津海特传动机械有限公司| 邯郸市复液液压机械有限公司| 浙江高达机械有限公司| 济南欧亚德数控机械有限公司| 山东山推机械有限公司| 东莞市新望包装机械有限公司| 汕头机械厂有限公司| 浙江陀曼精密机械有限公司| 广西 机械 有限公司| 赵县金利机械有限公司| 山东旭升机械有限公司| 佛山市液压机械有限公司| 武汉中粮机械有限公司| 张家港市亿利机械有限公司| 山东神州机械有限公司| 武汉纵能机械制造有限公司| 百斯特机械有限公司| 江阴祥乐机械有限公司| 河南博众机械制造有限公司| 长沙力诺机械有限公司| 吉林牧神机械有限公司| 广州市广花包装机械有限公司| 常州机械制造有限公司| 郑州市建新机械制造有限公司 | 南通昭和机械有限公司| 机械制造有限公司 官网| 杭州海兴机械有限公司| 威海化工机械有限公司招聘| 山东平安工程机械有限公司| 桂林橡胶机械有限公司| 东莞协鑫机械有限公司| 广州市台展机械有限公司| 无锡力马化工机械有限公司| 天津动力机械有限公司| 郑州同鼎机械设备有限公司| 上海国翔包装机械制造有限公司| 广东富华重工制造有限公司| 威尔达重工有限公司| 杭州红磊机械有限公司| 黄山市机械有限公司| 东莞正扬电子机械有限公司怎么样| 青岛凯顿机械有限公司| 安微博达重工有限公司| 无锡市钢铁有限公司| 雅康精密机械有限公司| 广濑精密机械有限公司| 南通盛仕达精密机械有限公司| 佛山市浩铭达机械制造有限公司| 济南铭机械有限公司| 陕西机械制造有限公司| 杭州博创机械有限公司| 宁波隆源精密机械有限公司| 杭州双林机械有限公司| 中农丰茂植保机械有限公司| 河北实阳机械有限公司| 杭州萧山机械有限公司| 山东山建机械有限公司| 武汉泛洲机械制造有限公司| 山东大丰机械有限公司| 安徽唐兴机械装备有限公司| 江苏博森机械制造有限公司| 湖北天腾重型机械制造有限公司| 河北龙汐机械制造有限公司| 漳州市机械有限公司| 恒力泰机械有限公司| 莱州聚峰机械有限公司| 长沙昊博机械设备有限公司| 浙江斯耐达机械工具有限公司| 上海开隆冶金机械制造有限公司 | 食品有限公司起名大全| 起帆电线电缆有限公司| 安徽佳乐建设机械有限公司| 沈阳矿山机械有限公司| 山西瑞飞机械制造有限公司| 浙江超力机械有限公司| 台州华达机械有限公司| 南通科诚橡塑机械有限公司| 郑州亚美机械制造有限公司| 天津富启机械有限公司| 河北巨牛机械有限公司| 青岛弗林斯曼机械制造有限公司 | 上海化工机械厂有限公司| 上海开隆冶金机械制造有限公司| 成都欧曼机械有限公司| 山东宁联机械制造有限公司| 河南机械设备制造有限公司列表| 温岭林大机械有限公司| 威图电子机械技术上海有限公司| 兰州华诚石化机械制造有限公司| 郑州市鼎盛机械制造有限公司| 鹤壁市豫星机械制造有限公司| 沈阳 机械 有限公司| 北京工程机械有限公司| 泉州机械制造有限公司| 济南北斗星机械设备有限公司| 远洋翔瑞机械有限公司| 安徽联塔盛通机械制造有限公司 | 广东森人机械有限公司| 福州闽台机械有限公司| 鸿达机械制造有限公司| 东莞市台钢机械设备有限公司| 青岛雷沃工程机械有限公司| 苏州奥德机械有限公司| 广西柳工机械有限公司| 山东领品机械有限公司| 江阴市博越机械有限公司| 上海余特包装机械制造有限公司| 福州恒拓机械有限公司| 高义钢铁有限公司电话| 洛阳路通重工机械有限公司| 盛达机械设备有限公司| 合肥汉杰包装机械喷码有限公司| 佛山市洛德机械设备有限公司| 南海力丰机械有限公司| 禹城益佳机械有限公司| 山东亚泰机械有限公司| 寿光 机械有限公司| 苏州德伊捷自动化机械有限公司 | 中阳钢铁有限公司招聘| 日晗精密机械有限公司| 上海起鑫贸易有限公司| 上海海韬机械有限公司| 湖南信昌机械有限公司| 石家庄美迪机械有限公司| 江苏如皋钢铁有限公司| 温州博宇机械有限公司| 厦门机械制造有限公司| 杭州驰林机械有限公司| 江苏百德机械有限公司| 新美星包装机械有限公司 | 溧阳申特钢铁有限公司| 钢铁国际贸易有限公司| 温州朝隆纺织机械有限公司 | 浙江科力塑料机械有限公司| 碎得机械北京有限公司| 中船重工重庆液压机电有限公司| 上海石油机械有限公司| 上海圣起包装机械有限公司| 滕州市美力机械有限公司| 广州冠浩机械设备有限公司| 广东粤凯机械有限公司| 武汉包装机械有限公司| 杭州友高精密机械有限公司| 中石化机械有限公司| 上海熊猫机械有限公司| 淄博 机械有限公司| 南京苏荣机械有限公司| 南通太和机械有限公司| 湖南正中制药机械有限公司| 富达机械制造有限公司| 涞源奥宇钢铁有限公司| 东莞沃德精密机械有限公司| 广东金凯锐机械技术有限公司 | 江苏电能机械有限公司| 东莞正扬电子机械有限公司| 山东荣利中石油机械有限公司| 温岭联星机械有限公司| 青岛新东机械有限公司| 南京东部精密机械有限公司| 山东源泉机械有限公司| 河南甲庚机械设备有限公司| 南通龙威机械有限公司| 青岛正机械有限公司| 昆山河海精密机械有限公司| 丹阳荣嘉精密机械有限公司| 山东华伟重工机械有限公司| 恩德特机械(苏州)有限公司| 太仓越华精密机械配件有限公司 | 青岛昊悦机械有限公司| 张家港 机械有限公司| 江苏恩纳斯重工机械有限公司| 首钢伊犁钢铁有限公司| 西安冠杰机械设备有限公司 | 宝鸡万工机械制造有限公司| 济宁四通工程机械有限公司| 天津市华天世纪机械有限公司| 河北液压机械有限公司| 昆山河海精密机械有限公司| 绵阳动力机械有限公司| 江苏双箭输送机械有限公司| 青岛木业机械有限公司| 合肥春华起重机械有限公司| 新疆机械设备有限公司| 日晗精密机械有限公司| 广东精密机械有限公司| 常州万高机械制造有限公司| 群峰机械制造有限公司| 温州博大机械有限公司| 温州奋起皮业有限公司| 太平洋机械有限公司| 郑州水工机械有限公司招聘| 浙江青山钢铁有限公司| 佛山市洛德机械设备有限公司| 布勒常州机械有限公司| 安徽威萨重工机械有限公司 | 浙江瑞安机械有限公司| 烟台山一机械有限公司| 农业机械有限公司招聘| 厦门宇龙机械有限公司| 武汉四方圆机械设备有限公司| 东莞数控机械有限公司| 苏州圣亚精密机械有限公司| 济宁机械制造有限公司| 潍坊二川机械有限公司| 常州市日中精密机械有限公司 | 永宏机械制造有限公司| 莆田 机械有限公司| 昆山协扬机械有限公司| 本源兴(上海)包装机械材料有限公司| 无锡真木机械有限公司| 禹城通裕新能源机械铸造有限公司 | 青州康达机械有限公司| 上海太腾机械设备有限公司| 天盛机械制造有限公司| 山东亚泰重型机械有限公司| 廊坊百冠包装机械有限公司| 九江益鑫机械有限公司| 腾飞机械有限公司地址| 漳州市机械有限公司| 五矿钢铁上海有限公司| 温岭华驰机械有限公司| 泉州市工程机械有限公司| 青岛青工机械有限公司| 河北春耕机械制造有限公司| 山东济宁机械有限公司| 东莞市机械有限公司| 佛山市松可包装机械有限公司| 无锡通用机械有限公司| 扬州机械设备有限公司| 杭州萧山天成机械有限公司| 安丰钢铁有限公司地址| 江苏苏能机械有限公司| 全氏食品机械(上海)有限公司 | 温州利波机械有限公司| 青岛美克精密机械有限公司 | 西安新起航营销策划有限公司| 洛阳震动机械有限公司| 伯曼机械制造有限公司| 东莞市实诚机械有限公司| 上海鹰宏机械有限公司| 山西中阳钢铁有限公司| 山东重特机械有限公司| 上海山启机械制造有限公司| 无锡市川中五金机械有限公司| 海门亿峰机械有限公司| 盐城益聚达机械有限公司| 河南钢铁贸易有限公司| 深圳固尔琦包装机械有限公司| 扬州中孚机械有限公司| 上海爱德夏机械有限公司| 扬州精辉试验机械有限公司| 南皮县中顺环保机械有限公司| 重庆自动化机械有限公司| 河北中浩机械制造有限公司 | 陕西 机械有限公司怎么样| 青岛张氏机械有限公司| 德阳川广机械有限公司| 上海紫明印刷机械有限公司| 湖南力诺机械有限公司| 无锡市川中五金机械有限公司| 四川机械制造有限公司| 昆荣机械(昆山)有限公司| 上海铁美机械有限公司| 均强机械苏州有限公司| 昆山北钜机械有限公司| 南通太和机械有限公司| 山东恒升机械有限公司| 昆山总馨机械有限公司| 常州腾睿机械有限公司| 东莞市天成机械有限公司| 江苏飞耀机械制造有限公司| 金格瑞机械有限公司| 广州善友机械设备有限公司| 中阳钢铁有限公司电话| 河南三兄重工有限公司| 山东杰卓机械有限公司| 浙江温兄机械阀业有限公司| 川崎精密机械苏州有限公司| 温州奋起皮业有限公司| 新乡市威远机械有限公司| 昆山铁生机械有限公司| 上海博强机械有限公司| 洛阳泰红农业机械有限公司 | 重庆金丰机械有限公司| 勤堡精密机械有限公司| 孝感金达钢铁有限公司| 北京机械设备有限公司| 贵州凯星液力传动机械有限公司 | 宁波隆源精密机械有限公司| 山东造纸机械厂有限公司| 无锡旭辉机械有限公司| 东平开元机械有限公司| 浙江盛维机械有限公司| 杭州金鸥机械有限公司| 上海新麦机械设备制造有限公司| 宁波博旺机械有限公司| 上海久协机械设备有限公司| 浙江超力机械有限公司| 河南兴远起重机有限公司| 无锡威马机械有限公司| 青岛国森机械有限公司| 苏州机械制造有限公司| 宁波永博机械制造有限公司| 伟业机械制造有限公司| 江阴乐帕克智能机械有限公司| 常州市日中精密机械有限公司| 铜陵群力机械有限公司| 北海船舶重工有限公司| 江苏威鹰机械有限公司| 兴世机械制造有限公司| 上海朗惠包装机械有限公司| 山东临沂机械有限公司| 三和水工机械有限公司| 佛山市中牌机械有限公司| 山东首钢钢铁贸易有限公司 | 济南科华机械有限公司| 东莞丰堡精密机械有限公司| 潍坊华星机械有限公司| 天津润澍机械有限公司| 湖南长河机械有限公司| 浙江万能弹簧机械有限公司| 长江液压机械有限公司| 山东国新起重机械有限公司| 诚辉机械制造有限公司| 无锡双益精密机械有限公司| 珠海机械设备有限公司| 句容立成强机械有限公司| 邢台德龙钢铁有限公司招聘| 东泰机械制造有限公司| 宁波市北仑机械制造有限公司| 志庆机械设备有限公司| 温州国伟印刷机械有限公司| 捷赛机械苏州有限公司| 江苏 重型机械有限公司| 上海太腾机械设备有限公司 | 东风井关农业机械有限公司 | 大连正丰机械有限公司| 南通凯迪自动机械有限公司| 苏州海骏自动化机械有限公司 | 富阳液压机械有限公司| 上海翔展机械有限公司| 浙江陀曼精密机械有限公司| 恩比尔(厦门)机械制造有限公司| 芜湖 机械制造有限公司| 烟台莫深机械设备有限公司 | 常州常发动力机械有限公司| 涿州北方重工设备设计有限公司| 马鞍山市机械有限公司| 东莞高臻机械设备有限公司| 河南省平原矿山机械有限公司| 靖江 机械有限公司| 江阴兴澄特种钢铁有限公司| 苏州宇钻机械有限公司| 苏州辽鞍机械有限公司| 瑞安 包装机械有限公司| 南京赛达机械制造有限公司| 恒利达机械有限公司| 张家口机械有限公司| 钦州力顺机械有限公司| 苏州勤堡精密机械有限公司 | 润源经编机械有限公司| 山东通佳重工有限公司| 荣精密机械有限公司| 阿特拉斯机械设备有限公司| 青岛欧普机械设备有限公司| 佛山市南海鼎工包装机械有限公司 | 武汉益达建设机械有限公司| 天津文洲机械有限公司| 青岛迪恩机械制造有限公司| 杭州莱顿机械有限公司| 江苏中热机械设备有限公司| 上海冉本机械制造有限公司 | 玉环宝捷机械有限公司| 青岛海佳机械有限公司| 郑州志乾机械设备有限公司| 扬州鼎隆机械有限公司| 郑州重工机械有限公司| 无锡好麦机械有限公司| 利星行机械昆山有限公司| 德阳瑞隆机械有限公司| 保定金地机械有限公司| 西安金力特机械设备有限公司| 江苏甲钢钢铁有限公司| 佛山定中机械有限公司| 锦州天晟重工有限公司| 快克数控机械有限公司| 恒联食品机械有限公司| 宜春江特机械传动有限公司| 江苏三麦食品机械有限公司| 青岛谊金华塑料机械有限公司| 南通棉花机械有限公司| 安徽中晨机械有限公司| 河南信联重工机械有限公司| 上海舜锋机械制造有限公司| 上海胜松机械制造有限公司 | 天翔机械制造有限公司| 梧州沃华机械有限公司| 北京骏马机械有限公司| 广州众起办公用品有限公司 | 浙江金驰机械有限公司| 河南奥创机械设备有限公司| 龙工江西机械有限公司| 江苏久保田农机机械有限公司| 广州通泽机械有限公司| 洛阳泰红农业机械有限公司| 郑州重工机械有限公司| 湖南申德钢铁有限公司| 常州市雪龙机械制造有限公司| 淄博捷达机械有限公司| 河南省中原起重机械有限公司 | 上海精密机械有限公司| 东莞市茂丰机械有限公司| 东莞启益电器机械有限公司 | 烟台市石油机械有限公司 | 小松工程机械有限公司| 济宁鑫宏工矿机械设备有限公司 | 襄阳通威机械有限公司| 昆山 环保机械有限公司| 湖北三六重工有限公司| 上海斯特克沃森重工设备有限公司 | 天阳机械制造有限公司| 台州嘉瑞机械有限公司| 北京刷机械有限公司| 首钢凯西钢铁有限公司| 温州华珍机械有限公司| 机械有限公司 张家港| 粮食机械设备有限公司| 济南大鹏机械设备有限公司| 泉州机械设备有限公司| 山东章晃机械工业有限公司| 新乡天丰机械有限公司| 上海舒平精工机械有限公司| 南京科倍隆机械有限公司| 济南中唐机械设备有限公司| 温岭林大机械有限公司| 昆山合济机械有限公司| 扬州鼎隆机械有限公司| 丹阳市华泰制药机械有限公司 | 江苏维达机械有限公司| 合肥海源机械有限公司| 遵化建龙钢铁有限公司| 临清市机械有限公司| 浙江乐江机械有限公司| 邦贝液压机械有限公司| 山东华伟重工机械有限公司| 马鞍山市机械有限公司| 山东浩信机械有限公司| 宁波宁塑机械有限公司| 宇进注塑机械有限公司| 广州金本机械设备有限公司| 青岛纺织机械有限公司| 厦门大金机械有限公司| 苏州科瑞机械有限公司| 广州市德晟机械有限公司| 江苏东钢钢铁有限公司| 东莞市鼎祥通用机械设备有限公司 | 湖南工程机械有限公司| 浙江瑞德森机械有限公司| 重庆金丰机械有限公司| 上海明硕机械有限公司| 全氏食品机械(上海)有限公司| 杭州萧山凯兴食品机械有限公司| 新疆 机械有限公司| 山东钢铁贸易有限公司| 杭州一鼎传动机械有限公司| 建友机械设备有限公司| 西帕机械杭州有限公司| 广州美特机械有限公司| 仙游东亚机械有限公司| 无锡布勒机械制造有限公司招聘| 西安星火包装机械有限公司| 重庆庆泰机械有限公司| 山东机械设备有限公司怎么样| 洛阳重型机械有限公司| 正扬电子机械有限公司| 桐乡合德机械有限公司| 浙江四和机械有限公司| 九江萍钢钢铁有限公司电话| 青州市晨光机械有限公司| 东莞培锋精密机械有限公司| 东莞市纳金机械有限公司| 山西中德科工机械制造有限公司| 东莞市金坤机械设备有限公司 | 上海以海机械有限公司| 天津润机械有限公司| 福州六和机械有限公司| 东莞市博志达工程机械制造有限公司| 厦门群鑫机械工业有限公司| 洛阳福格森机械装备有限公司 | 深圳精机械有限公司| 德瑞机械设备有限公司| 浙江鼎业机械设备有限公司| 苏州施米特机械有限公司| 唐山国义特种钢铁有限公司| 江苏金荣机械有限公司| 上海春日机械工业有限公司| 浙江金马逊机械有限公司| 浙江鼎业机械设备有限公司| 山东钢铁贸易有限公司| 溧阳机械制造有限公司| 上海五金机械有限公司| 力 机械 有限公司| 南通 机械有限公司| 江阴市豪亚机械制造有限公司| 泉州机械设备有限公司| 宁波科鼎钢铁有限公司| 昆山市升达机械制造有限公司| 宏祥建筑机械有限公司| 杭州春江制药机械有限公司| 浙江宏华机械塑胶有限公司| 青岛莱恩机械有限公司| 江苏江海机械有限公司| 江苏宏博机械制造有限公司| 新乡矿山起重机有限公司| 斯特精密机械有限公司| 江阴市豪亚机械制造有限公司| 东莞市嘉鲁特注塑机械有限公司| 杭州容瑞机械技术有限公司| 日照兴业机械有限公司| 杭州海铭钢铁有限公司| 唐山佳鑫机械配件有限公司| 江苏科圣化工机械有限公司 | 济南沃德机械制造有限公司| 三一众力机械有限公司| 浙江瑞安机械有限公司| 迪砂常州机械有限公司| 中交天和机械设备制造有限公司| 无锡南机械有限公司| 河南矿山起重机有限公司销售电话 | 唐山前进钢铁有限公司| 山东泰瑞汽车机械电器有限公司| 青岛农业机械有限公司| 久隆久兴机械有限公司| 江苏红日钢铁有限公司| 郑州万谷机械有限公司| 青岛金福鑫塑料机械有限公司| 张家港港龙机械有限公司| 山东常美机械有限公司| 山东愚公工程机械有限公司| 广东佳明重工有限公司| 常州精密机械有限公司| 宝钢盐城钢铁有限公司| 湖南中一惠龙机械设备有限公司| 利勃海尔机械大连有限公司| 诸城市天顺机械有限公司| 常州 重工有限公司| 常州度盛机械有限公司| 无锡威马机械有限公司| 上海板换机械设备有限公司| 济宁朝阳机械有限公司| 科润达机械有限公司| 苏州昶智精密机械有限公司| 石化机械制造有限公司| 句容立成强机械有限公司| 江苏中饮机械有限公司| 自动化机械设备有限公司| 新乡市海纳筛分机械制造有限公司| 诸城科翔机械有限公司| 青岛春风机械有限公司| 台林机械有限公司 -| 昆明远桥机械有限公司| 宁波丰州机械有限公司| 长沙市机械有限公司| 上海曼亿包装机械有限公司| 太行机械工业有限公司| 龙岩市机械有限公司| 湘元三一机械有限公司| 河南省新乡市矿山起重机有限公司| 浙江省机械有限公司| 温州市凯驰包装机械有限公司| 山东鲁新起重设备有限公司 | 徐州液压机械制造有限公司| 河南 机械制造有限公司| 河北州科重工有限公司| 南京高立工程机械有限公司| 江阴市勤业化工机械有限公司| 首钢东华机械有限公司| 广州市 工程机械有限公司| 苏州友众传动机械有限公司| 杰西博工程机械有限公司| 新乡市佳盛振动机械有限公司| 常州布勒机械有限公司| 石油机械设备有限公司| 浙江德鹏机械有限公司| 沈阳三重机械有限公司| 常州新燎原机械有限公司| 浙江工程机械有限公司| 机械有限公司 南丰| 佛山市洛德机械设备有限公司| 滕州三合机械有限公司| 东莞%机械制造有限公司| 路通重工机械有限公司| 江苏 重型机械有限公司| 河南小松工程机械有限公司| 浙江德迈机械有限公司| 东莞市金坤机械设备有限公司| 山东鲁一机械有限公司| 中山 机械 有限公司| 河南万杰食品机械有限公司| 泉州恒泉机械有限公司| 上海西马特机械制造有限公司| 济南机械设备有限公司| 河南人从众机械制造有限公司| 上海皆力机械设备有限公司| 饶阳鸿源机械有限公司| 广州市科展机械设备有限公司| 德州锦冠钢铁有限公司| 湖北华伟石化机械设备制造有限公司 | 济南建设机械有限公司| 金格瑞机械有限公司| 天津工程机械有限公司| 浙江三永机械有限公司| 江苏隆达机械设备有限公司 | 诸城市机械有限公司| 派菲奥机械有限公司| 海狮洗涤机械有限公司| 南通宝顺机械有限公司| 山东章晃机械工业有限公司| 东台富康机械有限公司| 河南省起重机有限公司| 山东兴华机械有限公司| 博山华翔机械制造有限公司| 招远华丰机械设备有限公司| 上海钢铁交易中心有限公司 | 福建瑜鼎机械有限公司| 河北冀工机械制造有限公司| 济南升降机械有限公司| 湖南一田农业机械有限公司| 山东鲁工机械有限公司| 郑州恒科机械有限公司| 成机械设备有限公司| 杭州海纳机械有限公司| 诸城顺德机械有限公司| 大连 橡塑机械有限公司| 湖州天和机械有限公司| 机电设备有限公司起名| 珠海市机械设备有限公司| 广东达诚机械有限公司| 郑州水工机械有限公司招聘| 浙江园林机械有限公司| 辽宁天亿机械有限公司| 泰安古河机械有限公司| 台湾晁群机械有限公司| 昆成机械昆山有限公司| 中船重工环境工程有限公司| 杭州海纳机械有限公司| 南通科诚橡塑机械有限公司 | 东莞市联顺机械有限公司| 无锡钢铁贸易有限公司| 斗山工程机械有限公司| 无锡名震机械制造有限公司| 安庆佳乐机械有限公司| 珠海市机械有限公司| 卓郎新疆智能机械有限公司| 广西玉柴动力机械有限公司| 上海科熙起重设备有限公司 | 浙江濠泰机械有限公司| 常州市雪龙机械制造有限公司| 无锡械锐机械有限公司| 涿州北方重工设备设计有限公司 | 浙江美华包装机械有限公司| 机械密封件有限公司| 青岛美光机械有限公司| 南通丰威机械有限公司| 基伊埃机械设备天津有限公司| 无纺布机械有限公司| 广州机械有限公司 v| 济南金胜星机械设备有限公司| 杭州力士机械有限公司| 浙江美华包装机械有限公司| 济南 升降机械有限公司| 苏州信能精密机械有限公司| 上海重工机械有限公司| 郑州鑫宇机械制造有限公司| 杭州雅顿过滤机械有限公司| 威图电子机械技术上海有限公司| 江苏石油机械有限公司| 英侨机械制造有限公司| 北京机械设备有限公司| 南通太和机械有限公司| 利勃海尔机械大连有限公司| 南通中船机械制造有限公司| 南京泽创机械有限公司| 江阴市永昌药化机械有限公司| 聊城 机械有限公司| 常德机械制造有限公司| 南京星德机械有限公司| 上海冠龙阀门机械有限公司官网| 宁波东泰机械有限公司| 临沂新天力机械有限公司| 南通凯迪自动机械有限公司| 林州中奥机械有限公司| 昆山弘迪精密机械有限公司 | 大连矢岛机械有限公司| 杭州联德机械有限公司| 安徽金锡机械有限公司| 鸿兴织带机械有限公司| 济南业兴通工程机械有限公司 | 苏州牧天动力机械有限公司| 河南省矿山起重有限公司| 诸暨市机械有限公司| 苏州五金机械有限公司| 丝网机械 有限公司| 泉州恒泉机械有限公司| 安丘博阳机械制造有限公司| 浙江青山钢铁有限公司| 浙江鼎力机械有限公司| 安徽矿山机械有限公司| 鑫达机械设备有限公司| 宝鸡市机械有限公司| 山东建筑机械有限公司| 河南起重设备有限公司| 湘潭 机械制造有限公司| 北京刷机械有限公司| 湖北粮食机械有限公司| 浙江高达机械有限公司| 杭州兴达机械有限公司| 华威机械制造有限公司| 杭州力诺机械设备有限公司| 佛山机械制造有限公司| 江苏普格机械有限公司| 上海京雅机械有限公司| 群峰机械制造有限公司| 洛阳矿山机械有限公司| 赣云食品机械有限公司| 沈阳凯力拓机械设备有限公司| 大连吉利机械配件有限公司| 上海天勇机械设备有限公司| 山东联亿重工有限公司| 杭州纳源传动机械有限公司| 钦州力顺机械有限公司| 上海金纬机械有限公司| 宁波东泰机械有限公司| 石家庄煤矿机械有限公司| 杭州一鼎传动机械有限公司| 恒泰机械制造有限公司| 大连工程机械有限公司| 精密机械设备有限公司| 长沙益广制药机械有限公司| 浙江鑫辉机械有限公司| 浙江永创机械有限公司| 厦门黎明机械有限公司| 常州迈腾机械有限公司| 成都的起重有限公司| 长沙威沃机械制造有限公司 | 深圳优捷机械有限公司| 莒县长运机械有限公司| 润源经编机械有限公司| 南通明诺机械有限公司| 上海建冶重工机械有限公司 | 杭州一鼎传动机械有限公司| 威海机械制造有限公司| 无锡东元精密机械有限公司| 河北凯瑞重工有限公司| 河南卫华重型机械有限公司| 徐州工程机械有限公司| 张家港精密机械有限公司| 广州市金王机械设备有限公司 | 长沙宏银机械有限公司| 青岛鲁耕农业机械有限公司 | 泰安海松机械有限公司| 泰安东岳重工有限公司| 无锡海天机械有限公司| 徐州 机械制造有限公司| 宁海奇精机械有限公司| 河北德林机械有限公司| 固达机械制造有限公司| 北京机械设备制造有限公司| 中意机械苏州有限公司| 高义钢铁有限公司电话| 新疆昆玉钢铁有限公司| 浙江保龙机械有限公司| 石家庄 机械有限公司| 鼎工机械制造有限公司| 深圳美鹏机械设备有限公司| 宁波市海达塑料机械有限公司| 机械(昆山)有限公司| 青岛德固特机械制造有限公司| 江苏合丰机械制造有限公司| 成都 食品机械有限公司| 常州玫尔机械有限公司| 广州普耐柯数控机械有限公司| 滕州三合机械有限公司| 山东泰安机械有限公司| 陕西机械制造有限公司| 恩比尔(厦门)机械制造有限公司| 济南蓝象数控机械有限公司| 山东欣弘发机械有限公司| 常州超通机械有限公司| 科华机械制造有限公司| 杭州 机械设备有限公司| 艾沃意特机械设备制造有限公司| 上海起重机械有限公司| 天津石油机械有限公司| 宜兴永康机械有限公司| 上海尼法机械有限公司| 河北常富机械有限公司| 泉州巨能机械有限公司| 深圳塑胶机械有限公司| 上海傣纬机械设备有限公司| 温岭市大众精密机械有限公司| 源通机械设备有限公司| 上海利昆机械有限公司| 江苏 重型机械有限公司| 上海久协机械设备有限公司| 上海众和包装机械有限公司| 机械(上海)有限公司| 上海楚尚机械有限公司| 上海冠龙机械有限公司| 青岛奥硕数控机械有限公司| 上海远跃制药机械有限公司| 上海舒平精工机械有限公司| 河南矿山机械有限公司| 嵩县煜嵩机械有限公司| 杭州恒宏机械有限公司| 东莞液压机械有限公司| 兰州长征机械有限公司| 无锡械锐机械有限公司| 郑州同鼎机械设备有限公司 | 上海杉野机械有限公司| 东莞木工机械有限公司| 昆山河海精密机械有限公司| 福建三宝钢铁有限公司| 山东广富钢铁有限公司| 建湖县液压机械有限公司| 济宁市兴旺机械制造有限公司| 浙江海工机械有限公司| 江苏鸡煤机械有限公司| 杭州冠浩机械设备有限公司| 上海亚华印刷机械有限公司| 南京华创包装机械设备有限公司| 青岛西城铸造机械有限公司| 晋工机械有限公司官网| 江阴惠尔信机械有限公司| 苏州在田机械有限公司| 广东思沃精密机械有限公司| 苏州工业园区机械有限公司| 上海合升机械有限公司| 苏州诚亚机械有限公司| 广州乾能机械制造有限公司| 慈溪科傲机械有限公司| 建湖县液压机械有限公司| 青岛山森机械有限公司| 东宇机械设备有限公司| 四川沱江起重机有限公司| 广州南头机械有限公司| 江苏苏盐阀门机械有限公司| 上海起华机械有限公司| 念朋机械设备有限公司| 青岛美嘉隆包装机械有限公司| 京山力拓机械有限公司| 南京机械制造有限公司| 苏州鸿本机械制造有限公司| 鼎龙机械制造有限公司| 新乡市振英机械设备有限公司| 南京苏荣机械有限公司| 郑州宇机械有限公司| 玉环锐利机械有限公司| 上海春明机械制造有限公司 |