Nested serializers in drf throws error with one to one field - django

My input json is :
{
"availability": "Current",
"drive_type": [{
"drive_name": "drive1",
"requirements": {
"performance_unit": "by_iops",
}
}]
}
I am getting error Cannot assign "
OrderedDict([('performance_unit', 'Basic')])":
"DriveType.requirements" must be a "Requirements" instance
.I am not able to figure it out to map in create method for one to one fields in tables
Below are my models.py
class ProductLine(models.Model):
availability = models.CharField(max_length=20, blank=True, null=True)
class Meta:
db_table = "product_line"
class DriveType(models.Model):
drive_name = models.CharField(max_length=20, blank=True, null=True)
product_line = models.ForeignKey(ProductLine, related_name="drive_type")
class Meta:
db_table = "drive_type"
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name="requirements")
class Meta:
db_table = "requirements"
Serializers.py :
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer(many = True)
class Meta:
model = DriveType
fields = (
"drive_name","workload_type")
class ProductLineSerializer(serializers.ModelSerializer):
drive_type = DriveTypeSerializer(many=True)
class Meta:
model = ProductLine
fields = ('availability', "drive_type")
def create(self, validated_data):
print("validate_data",validated_data)
drive_type_data = validated_data.pop("drive_type")
product_line = ProductLine.objects.create(**validated_data)
for drive_data in drive_type_data:
drive_type = DriveType.objects.create(product_line=product_line, **drive_data)
return product_line

You have one to one relationship of DriveType and Requirements
So remove many = True from DriveTypeSerializer for RequirementsSerializer
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer()
class Meta:
model = DriveType
fields = ("drive_name","workload_type")
Your input json has only one object of requirements not a list

Related

django-import-export how to deal with the import_id_fields is unique_together key?

the parentmodel is
class Work(models.Model):
po = models.ForeignKey(Po, verbose_name="合同号", on_delete=models.CASCADE)
remark = models.CharField(max_length=100, verbose_name="备注说明")
create_time=models.DateField(verbose_name="日期")
class Meta:
verbose_name = "工作清单"
verbose_name_plural = verbose_name
unique_together=("po","remark")
def __str__(self):
return self.remark
and the children model is
class Acceptance(models.Model):
work = models.ForeignKey(Work, on_delete=models.CASCADE, verbose_name="工作清单")
detail=models.ForeignKey(Detail,on_delete=models.CASCADE,verbose_name="验收物品")
accecpt_time = models.DateField(verbose_name="验收日期")
num = models.IntegerField(verbose_name="验收数量", validators=[MinValueValidator(1)])
person = models.CharField(max_length=100, verbose_name="验收人员")
class Meta:
verbose_name = "验收清单"
verbose_name_plural = verbose_name
unique_together=("accecpt_time","work")
I want to ask about how to defind the Acceptance Resource when the work foreign_key is unique_together key?
my test code is
class AcceptanceSource(resources.ModelResource):
work = fields.Field(attribute="work", widget=ForeignKeyWidget(Work, 'remark'), column_name="工作清单")
detail = fields.Field(attribute="detail", widget=ForeignKeyWidget(Detail, "name"), column_name="物料清单")
po = fields.Field(attribute="work__po", column_name="合同号", widget=ForeignKeyWidget(Po, "po_num"))
num = fields.Field(attribute="num", column_name="验收数量")
accecpt_time = fields.Field(attribute="accecpt_time", column_name="验收时间")
person = fields.Field(attribute="person", column_name="验收人员")
but it get error like this:
行号: 1 - get() returned more than one Work -- it returned 2!

DRF model serializer foreign key return object, not ID

when serialising a foreign key object, I'll get the object ID instead of the object. Any advise on how to get the object excluding the PK is greatly appreciated.
Output:
"biosamples": [
{
"short_form": "BTO_0004725",
"label": "embryonic fibroblast",
"ontology": 1
}
],
Models:
class Biosample(models.Model):
biosample_id = models.AutoField(primary_key=True)
ontology = models.ForeignKey('Ontology', models.DO_NOTHING, related_name='biosample_ontologies')
short_form = models.CharField(max_length=255, unique=True )
label = models.CharField(max_length=255)
class Meta:
managed = True
db_table = 'biosample'
def __str__(self):
return self.label
class Ontology(models.Model):
ontology_id = models.AutoField(primary_key=True)
name = models.CharField(unique=True, max_length=255)
short_name = models.CharField(max_length=255)
url = models.CharField(max_length=255)
base_url = models.CharField(max_length=255)
rest_base_url = models.CharField(max_length=255)
prefix = models.CharField(max_length=255, unique=True)
class Meta:
managed = True
db_table = 'ontology'
def __str__(self):
return self.name
Serializers:
class OntologieSerializer(base.ObjectSerializer):
class Meta:
model = Ontology
fields = '__all__'
class BiosampleSerializer(base.ObjectSerializer):
class Meta:
model = Biosample
fields = '__all__'
ontology = OntologieSerializer(hidden=['ontology_id'])
ObjectSerializer (Data is read from a spreadsheet, strings need to be empty to load):
class ObjectSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
data = super().to_representation(instance)
# Need empty string for loading
return {key: ('' if data[key] is None else value) for key, value in data.items()}
Thanks!
Indentation error, ontologie ended upin class Meta
class BiosampleSerializer(base.ObjectSerializer):
class Meta:
model = Biosample
fields = '__all__'
#Culprit:
ontology = OntologieSerializer(hidden=['ontology_id'])

How to do a relationship using DRF to another table without foreignKey

I can not do relatioships between two tables without relationships.
My models are :
class exampleModel(models.Model):
quantity = models.IntegerField(blank=False, null=True)
comment = models.CharField(max_length=100 , blank=True, null=True)
class Meta:
db_table = "example"
class Logger(models.Model):
id_table = models.IntegerField()
table = models.CharField(max_length=20 , blank=True, null=True)
comment = models.CharField(max_length=100 , blank=True, null=True)
action = models.CharField(max_length=100 , blank=True, null=True)
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "logger"
I already have filled logger Model, but , I have not be able made the exampleSerializer.
My serializers are:
class LoggerSerializer(serializers.ModelSerializer):
class Meta:
db_table = u'logger'
model = Logger
fields = '__all__'
class exampleSerializer(serializers.ModelSerializer):
last_log = LoggerSerializer(read_only=True)
class Meta:
db_table = 'example'
model = ExampleModel
fields = ( 'id' , 'last_log' , 'quantity')
in logger saves :
id_table : 'primary key of example',
table : 'example'
comment : 'custom comment',
action : "CRUD"
You can query last logger in view, then pass it to serializer in context.
Then do something like:
class exampleSerializer(serializers.ModelSerializer):
last_log = serializers.SerializerMethodField()
class Meta:
db_table = 'example'
model = ExampleModel
fields = ('id', 'last_log', 'quantity')
def get_last_log(self, obj):
last_log = obj.state(self.context['last_log'])
last_log_serializer = LoggerSerializer(last_log)
return last_log_serializer.data
You pass to context, with something like:
exampleSerializer(queryset, context ={'last_log': last_log_object})
Also You can do the query in exampleSerializer:
class exampleSerializer(serializers.ModelSerializer):
last_log = serializers.SerializerMethodField()
class Meta:
db_table = 'example'
model = ExampleModel
fields = ('id', 'last_log', 'quantity')
def get_last_log(self, obj):
logger_queryset =Logger.objects.filter(table = self.Meta.db_table, id_table = obj.id)
return LoggerSerializer(logger_queryset).data

Django Rest Framework get attributes from foreign key's class

here's my models:
class Recruteur(models.Model):
entrepriseName = models.CharField(max_length=50)
emplacement = models.CharField(max_length=50)
class Offre(models.Model):
title = models.CharField(max_length=100, blank=True, default=0)
idRecruteur = models.ForeignKey(Recruteur,verbose_name = "idRecruteur", on_delete=models.CASCADE, default=None)
and here's my api.py:
class VilleViewSet(ModelViewSet):
queryset = Offre.objects.values('idRecruteur__emplacement').distinct()
serializer_class = VilleSerializer
serializers.py:
class EmplacementSerializer(serializers.ModelSerializer):
class Meta:
model = Recruteur
fields = ('emplacement',)
class VilleSerializer(serializers.ModelSerializer):
emplacements = EmplacementSerializer(source='idRecruteur', read_only=True)
class Meta:
model = Offre
fields = ( 'emplacements',)
i was expecting a result like this
but i got nothing instead ..
Any ideas why?
You get nothing, because there is no emplacements field in Offre model. I guess, what you want is to get serialized Recruteur record, that is referenced by idRecruteur field. Try this:
class VilleSerializer(serializers.ModelSerializer):
idRecruteur = EmplacementSerializer(read_only=True)
class Meta:
model = Offre
fields = ( 'idRecruteur',)

Nested Serializers with multiple tables not working

I have the below tables in models.py.
class ProductLine(models.Model):
availability = models.CharField(max_length=20, blank=True, null=True)
series = models.CharField(max_length=20, blank=True, null=True)
model = models.CharField(max_length=20, blank=True, null=True)
class Meta:
db_table = "product_line"
class DriveType(models.Model):
drive_name = models.CharField(max_length=20, blank=True, null=True)
product_line = models.ForeignKey(ProductLine, related_name="drive_type")
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True)
class Meta:
db_table = "requirements"
class WorkloadType(models.Model):
workload_type_options = models.CharField(max_length=50, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True)
class Meta:
db_table = "workload_type"
I have below serializers:
class WorkloadTypeSerializer(serializers.ModelSerializer):
class Meta:
model = WorkloadType
fields = "__all__"
class RequirementsSerializer(serializers.ModelSerializer):
class Meta:
model = Requirements
fields = "__all__"
class DriveTypeSerializer(serializers.ModelSerializer):
requirements = RequirementsSerializer(many = False, read_only = True)
workload_type = WorkloadTypeSerializer(many=False,read_only=True)
class Meta:
model = DriveType
fields = (
"drive_name", "available_drive_type", "capacity", "raid_type", "raid_size", "workload", "workload_percentage",
"raid_groups", "compression", "compression_value","requirements","workload_type")
class ProductLineSerializer(serializers.ModelSerializer):
drive_type = DriveTypeSerializer(many=True, read_only=True)
class Meta:
model = ProductLine
fields = ('availability','series','model','drive_type')
In my views I have this:
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
def get_queryset(self):
return ProductLine.objects.filter(id=self.kwargs.get("pk"))
serializer_class = ProductLineSerializer
I am getting output as below :
{
"availability": "Current",
"series": "3000",
"model": "2000",
"drive_type": [
{
"drive_name": "drive1",
"requirements": {
"drive_type": 2,
"performance_unit": "by_iops",
}
}
]
}
Why I am not able to see WorkLoadType tables data in json where as I am able to see Requirements data . I don't even see the field in json. Nested serializers only support a single relation tables
Answering my own question. Have to use related_name in the models for reverse relationship.
class Requirements(models.Model):
performance_unit = models.CharField(max_length=100, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name=requirements)
class Meta:
db_table = "requirements"
class WorkloadType(models.Model):
workload_type_options = models.CharField(max_length=50, blank=True, null=True)
drive_type = models.OneToOneField(DriveType,on_delete=models.CASCADE,primary_key=True,related_name=workload_type)