viewset tutorial perform_update framework example apiview python django django-views django-rest-framework

python - tutorial - django rest framework viewset



Obtenga la validación de parámetros en los conjuntos de vistas.ModelViewSet (3)

Soy nuevo en django y estoy creando una API REST usando django-rest-framework . He escrito algún código para verificar si el usuario ha suministrado algunos parámetros o no. Pero eso es muy feo con muchas if conditions , por lo que quiero refactorizarlo. A continuación se muestra el código que he escrito. Por favor, sugiera cómo refactorizarlo.

Estoy buscando algunas validaciones basadas en django.

class AssetsViewSet(viewsets.ModelViewSet): queryset = Assets.objects.using("gpr").all() def create(self, request): assets = [] farming_details = {} bluenumberid = request.data.get(''bluenumberid'', None) if not bluenumberid: return Response({''error'': ''BlueNumber is required.''}) actorid = request.data.get(''actorid'', None) if not actorid: return Response({''error'': ''Actorid is required.''}) asset_details = request.data.get(''asset_details'', None) if not asset_details: return Response({''error'': ''AssetDetails is required.''}) for asset_detail in asset_details: location = asset_detail.get(''location'', None) if not location: return Response({''error'': ''location details is required.''}) assettype = asset_detail.get(''type'', None) if not assettype: return Response({''error'': ''assettype is required.''}) asset_relationship = asset_detail.get(''asset_relationship'', None) if not asset_relationship: return Response({''error'': ''asset_relationship is required.''}) subdivision_code = location.get(''subdivision_code'', None) if not subdivision_code: return Response({''error'': ''subdivision_code is required.''}) country_code = location.get(''country_code'', None) if not country_code: return Response({''error'': ''country_code is required.''}) locationtype = location.get(''locationtype'', None) if not locationtype: return Response({''error'': ''locationtype is required.''}) latitude = location.get(''latitude'', None) if not latitude: return Response({''error'': ''latitude is required.''}) longitude = location.get(''longitude'', None) if not longitude: return Response({''error'': ''longitude is required.''}) try: country_instance = Countries.objects.using(''gpr'').get(countrycode=country_code) except: return Response({''error'': ''Unable to find country with countrycode '' + str(country_code)}) try: subdivision_instance = NationalSubdivisions.objects.using(''gpr'').get(subdivisioncode=subdivision_code, countrycode=country_code) except: return Response({''error'': ''Unable to find subdivision with countrycode '' + str(country_code) + '' and'' + '' subdivisioncode '' + str(subdivision_code)}) kwargs = {} kwargs[''pobox''] = location.get(''pobox'', '''') kwargs[''sublocation''] = location.get(''sublocation'', '''') kwargs[''streetaddressone''] = location.get(''streetaddressone'', '''') kwargs[''streetaddresstwo''] = location.get(''streetaddresstwo'', '''') kwargs[''streetaddressthree''] = location.get(''streetaddressthree'', '''') kwargs[''city''] = location.get(''city'', '''') kwargs[''postalcode''] = location.get(''postalcode'', '''') cursor = connections[''gpr''].cursor() cursor.execute("Select uuid() as uuid") u = cursor.fetchall() uuid = u[0][0].replace("-", "") kwargs[''locationid''] = uuid # l.refresh_from_db() try: Locations.objects.using(''gpr'').create_location(locationtype=locationtype, latitude=latitude, longitude=longitude, countrycode=country_instance, subdivisioncode = subdivision_instance, **kwargs) except (TypeError, ValueError): return Response({''error'': ''Error while saving location''}) try: location_entry = Locations.objects.using(''gpr'').get(locationid=uuid) except: return Response({''error'': ''Unable to find location with locationid '' + str(uuid)}) asset_entry = Assets.objects.using(''gpr'').create(locationid=location_entry, assettype=assettype) asset_entry = Assets.objects.using(''gpr'').filter(locationid=location_entry, assettype=assettype).latest(''assetinserted'') farming_details[asset_entry.assetid] = [] try: actor = Actors.objects.using(''gpr'').get(actorid = actorid) except: return Response({''error'': ''Unable to find actor with actorid '' + str(actorid)}) assetrelationship = AssetRelationships.objects.using(''gpr'').create(assetid= asset_entry, actorid= actor,assetrelationship=asset_relationship) assets.append(asset_entry) if assettype=="Farm or pasture land": hectares = asset_detail.get(''hectares'', None) if hectares is None: return Response({''error'': ''hectares must be a decimal number''}) try: farmingasset = FarmingAssets.objects.using(''gpr'').create(assetid=asset_entry, hectares=hectares) except ValidationError: return Response({''error'': ''hectares must be decimal value.''}) farmingasset = FarmingAssets.objects.using(''gpr'').filter(assetid=asset_entry, hectares=hectares).last() for type_detail in asset_detail.get(''type_details'', []): crop = type_detail.get(''crop'', '''') hectare = type_detail.get(''hectare'', '''') if crop != '''' and hectare != '''': try: h3code = ProductCodes.objects.using(''gpr'').get(h3code=crop) except: return Response({''error'': ''Unable to find ProductCode with h3code'' + str(crop)}) try: farming = Farming.objects.using(''gpr'').create(assetid=farmingasset, h3code=h3code, annualyield=hectare) farming_details[asset_entry.assetid].append(farming.farmingid) except Exception as e: return Response({''error'': e}) else: return Response({''error'': ''crop with hectare is required.''}) i = 0 data = {} for asset in assets: if farming_details[asset.assetid]: data[i] = {"assetid": asset.assetid, "assetbluenumber": asset.assetuniversalid, "farming_ids": farming_details[asset.assetid]} else: data[i] = {"assetid": asset.assetid, "assetbluenumber": asset.assetuniversalid} i+=1 return Response(data)

Modelo de activo

class Assets(models.Model): assetid = models.CharField(db_column=''AssetID'', primary_key=True, max_length=255) # Field name made lowercase. assetname = models.CharField(db_column=''AssetName'', max_length=255, blank=True, null=True) # Field name made lowercase. locationid = models.ForeignKey(''Locations'', models.DO_NOTHING, db_column=''LocationID'') # Field name made lowercase. assetuniversalid = models.CharField(db_column=''AssetBluenumber'', unique=True, blank=True, null=True, max_length=255) # Field name made lowercase. assettype = models.CharField(db_column=''AssetType'', max_length=45, blank=True, null=True) # Field name made lowercase. assetinserted = models.DateTimeField(db_column=''AssetInserted'', blank=True, null=True, auto_now_add=True) # Field name made lowercase. assetupdated = models.DateTimeField(db_column=''AssetUpdated'', blank=True, null=True, auto_now=True) # Field name made lowercase.


Esta es solo una guía que puede seguir para refactorizar, por supuesto, muchas otras cosas pueden mejorarse al realizar esto:

  • hacer un ModelSerializer para modelos de activos
  • AssetsModelSerializer debe manejar la validación
  • dentro de AssettsModelSerializer agregue cualquier ModelSerializer relacionado (como Ubicaciones) que tenga una validación y representación específicas
  • mueva el método de creación a AssetsModelSerializer y solo maneje allí la creación del modelo
  • AssetModelSerializer debe proporcionar una representación específica (si es necesario)
  • AssetsViewSet está haciendo más de una cosa como veo (especialmente la última parte con objetos FarmingAssets) ¿puede dividir esa lógica en otra vista? o ruta?

Puedes hacer ModelSerializer , tienen una forma muy fácil de validar tus datos. Como en su caso, todos los campos parecen requeridos, se vuelve aún más fácil.

Crea un archivo en tu aplicación de API como:

serializers.py

#Import Serializers lib from rest_framework import serializers #Import your models here (You can put more than one serializer in one file) from assets.model import Assets #Now make you serializer class class AssetsSerializer(serializers.ModelSerializer): class Meta: model = Profile fields = ''__all__'' #This last line will put all the fields on you serializer #but you can also especify only some fields like: #fields = (''assetid'', ''assetname'')

En la vista, puede usar su clase de serializador (s) para validar sus datos.

vistas.py

#Serializers from assets.serializers import AssetsSerializer #Libraries you can use from django.http import Http404 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status class AssetsViewSet(viewsets.ModelViewSet): queryset = Assets.objects.using("gpr").all() def create(self, request): assets = [] farming_details = {} #Set your serializer serializer = AssetsSerializer(data=request.data) if serializer.is_valid(): #MAGIC HAPPENS HERE #... Here you do the routine you do when the data is valid #You can use the serializer as an object of you Assets Model #Save it serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Tomé todo esto de la documentación. Puedes aprender mucho haciendo el tutorial desde el sitio oficial. Espero que ayude.


Puedes hacer algo como:

for param in [''bluenumberid'', ''actorid'', ''asset_details'']: if param not in request.data.keys(): raise Response({''error'': ''%s is required.'' % param}) ... for asset_detail in asset_details: for param in [''location'', ..., ''longitude'']: if param not in asset_detail.keys(): raise Response({''error'': ''%s is required.'' % param})