Reputation: 3262
I make a page that lists all the existing vendors and modules that apply to each vendor. Here I need to change the status of modules (active or unactive), and if the module does not exist, but need to make it active then create it. It looks roughly like this.
Vendor1 module1/false module2/true module3/true .....
Vendor2 module1/false module2/true module3/true .....
.....
.....
models.py
class RfiParticipation(models.Model):
vendor = models.ForeignKey('Vendors', models.DO_NOTHING, related_name='to_vendor')
m = models.ForeignKey('Modules', models.DO_NOTHING, related_name='to_modules')
active = models.BooleanField(default=False)
user_id = models.IntegerField()
rfi = models.ForeignKey('Rfis', models.DO_NOTHING, related_name='to_rfi', blank=True, null=True)
timestamp = models.DateTimeField(auto_now=True)
To display it, I use ListCreateAPIView() class and nested serializer
serializer.py
class VendorModulesListManagementSerializer(serializers.ModelSerializer):
to_vendor = RfiParticipationSerializer(many=True)
class Meta:
model = Vendors
fields = ('vendorid', 'vendor_name', 'to_vendor',)
read_only_fields = ('vendorid', 'vendor_name', )
def create(self, validated_data):
validated_data = validated_data.pop('to_vendor')
for validated_data in validated_data:
module, created = RfiParticipation.objects.update_or_create(
rfi=validated_data.get('rfi', None),
vendor=validated_data.get('vendor', None),
m=validated_data.get('m', None),
defaults={'active': validated_data.get('active', False)})
return module
class RfiParticipationSerializer(serializers.ModelSerializer):
class Meta:
model = RfiParticipation
fields = ('pk', 'active', 'm', 'rfi', 'vendor', 'timestamp')
read_only_fields = ('timestamp', )
views.py
class AssociateModulesWithVendorView(generics.ListCreateAPIView):
"""
RFI: List of vendors with participated modules and modules status
"""
permission_classes = [permissions.AllowAny, ]
serializer_class = VendorModulesListManagementSerializer
queryset = Vendors.objects.all()
I have a question about using the create serializer method when sending a POST request.
Now the input format looks like this
{
"to_vendor": [
{
"active": false,
"m": 1,
"rfi": "20R1",
"vendor": 15
}]
}
I.e. the dictionary key for the current code implementation is the list of one dictionary. If I remove " [] " from dict value I got
{
"to_vendor": {
"non_field_errors": [
"Expected a list of items but got type \"dict\"."
]
}
}
And this is the reason why I need to add a for loop in the create method to iterate through the list with just one element. I already have any doubts that I'm doing the right thing. Maybe I chose the wrong implementation way?
But now question is why do I get a mistake?
AttributeError: Got AttributeError when attempting to get a value for field `to_vendor` on serializer `VendorModulesListManagementSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `RfiParticipation` instance.
Original exception text was: 'RfiParticipation' object has no attribute 'to_vendor'.
I would be very grateful for your help and advice!
upd
Get request format data:
[
{
"vendorid": 15,
"vendor_name": "Forest Gamp",
"to_vendor": [
{
"pk": 35,
"active": true,
"m": "Sourcing",
"rfi": "1",
"vendor": 15,
"timestamp": "2020-03-29T08:15:41.638427"
},
{
"pk": 39,
"active": false,
"m": "CLM",
"rfi": "20R1",
"vendor": 15,
"timestamp": "2020-03-29T09:09:03.431111"
}
]
},
{
"vendorid": 16,
"vendor_name": "Test21fd2",
"to_vendor": [
{
"pk": 41,
"active": false,
"m": "SA",
"rfi": "20R1",
"vendor": 16,
"timestamp": "2020-03-30T11:05:16.106412"
},
{
"pk": 40,
"active": false,
"m": "CLM",
"rfi": "20R1",
"vendor": 16,
"timestamp": "2020-03-30T10:40:52.799763"
}
]
}
]
Upvotes: 0
Views: 763
Reputation: 558
I have gone through your implementation, and I suppose you might have used wrong generics class inheritance in views.py.
You should try to replace
class AssociateModulesWithVendorView(generics.ListCreateAPIView):
permission_classes = [permissions.AllowAny, ]
serializer_class = VendorModulesListManagementSerializer
queryset = Vendors.objects.all()
With
class AssociateModulesWithVendorView(generics.CreateAPIView, generics.ListAPIView):
permission_classes = [permissions.AllowAny, ]
serializer_class = VendorModulesListManagementSerializer
queryset = Vendors.objects.all()
You can check below links for reference: CreateAPIView : https://www.django-rest-framework.org/api-guide/generic-views/#createmodelmixin ListCreateAPIView : https://www.django-rest-framework.org/api-guide/generic-views/#listcreateapiview
Upvotes: 0
Reputation: 1543
It tries to access to_vendor
on your model RfiParticipation
and it complains that this property does not exist. related_name
refers to the back relation on your Vendors
model. So that you can do something like Vendors.to_vendor.all()
and fetch all the RfiParticipation
instances.
This happens when it tries to validate your input data, so even before it gets to the create function of your serializer.
If you are trying to create new RfiParticipation
, why would you use a view that defines queryset = Vendors.objects.all()
?
Instead define a view that takes care of creating RfiParticipation
, since it seems that you already have a reference to Vendors
. If I understand correctly, what you are trying to do is basically batch create RfiParticipation
, so make a view that points to these.
Upvotes: 1