rest_marshmallow: Nested Schema isn't loading - python

I have trouble getting the nested Schema loaded using marshmallow serializer.
models.py
from django.db import models
class User(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.CharField(max_length=200, unique=True)
created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
class Upload(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
state = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
class Location(models.Model):
upload = models.ForeignKey(Upload, on_delete=models.CASCADE)
lat = models.FloatField()
long = models.FloatField()
serializers.py
from rest_marshmallow import Schema, fields
class LocationSchema(Schema):
lat = fields.String()
long = fields.String()
class UploadsSchema(Schema):
id = fields.Integer()
state = fields.String()
location = fields.Nested(LocationSchema)
user_id = fields.Integer()
created = fields.DateTime()
class UserSchema(Schema):
id = fields.Integer()
first_name = fields.String()
last_name = fields.String()
email = fields.Email()
created = fields.DateTime()
last_updated = fields.DateTime()
views.py
class UploadsView(ListView):
def get(self, request, user_id):
upload = Upload.objects.filter(user_id=user_id)
serializer = UploadsSchema(upload, many=True)
return JsonResponse(serializer.data, safe=False)
def post(self, request, user_id):
data = json.loads(request.body)
user = User.objects.get(id=user_id)
upload = Upload(state=data['state'], user=user)
upload.save()
recent_upload = Upload.objects.filter(user_id=user_id).latest('created')
location = Location(lat=data['lat'], long=data['long'], upload=recent_upload)
location.save()
message = {
"data": "Success"
}
return JsonResponse(message, safe=False)
GET on UploadsView returns all the fields except the Nested field.
Here's a sample response:
{
"user_id": 2,
"id": 5,
"created": "2022-08-05T17:44:30.829087+00:00",
"state": "happy"
}
I tried location = fields.Nested(LocationSchema(many=True)), but that doesn't seem to work either. What am I doing wrong here? TIA.

Related

Django(DRF) Null field in client address

I'm trying to save client details .
below is models.py:
class Address(models.Model):
street_address_line_1 = models.CharField(max_length=50)
street_address_line_2 = models.CharField(max_length=50)
city = models.CharField(max_length=50)
state = models.CharField(max_length=50)
zip = models.IntegerField()
country = models.CharField(max_length=50)
class Client(models.Model):
primary_contact_first_name = models.CharField(max_length=50)
primary_contact_last_name = models.CharField(max_length=50)
primary_contact_email = models.CharField(max_length=50, unique=True)
primary_contact_phone_number = models.CharField(max_length=50, unique=True)
primary_contact_phone_type = models.CharField(max_length=50)
secondary_contact_first_name = models.CharField(max_length=50)
secondary_contact_last_name = models.CharField(max_length=50)
secondary_contact_email = models.CharField(max_length=50, unique=True)
secondary_contact_phone_number = models.CharField(max_length=50, unique=True)
secondary_contact_phone_type = models.CharField(max_length=50)
client_address = models.ForeignKey(Address,related_name="client_address",on_delete=models.CASCADE, null=True, blank=False)
def __str__(self):
return self.primary_contact_email
and views.py:
#api_view(["POST"])
def createClientView(request):
if request.method == "POST":
serializer = ClientSerializer(data=request.data, many=False)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_200_OK)
error = Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return error
and serializers.py:
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = [
"street_address_line_1",
"street_address_line_2",
"city",
"state",
"zip",
"country",
]
class ClientSerializer(serializers.ModelSerializer):
address = AddressSerializer(source="addresss",read_only=True)
class Meta:
model = Client
fields = [
"primary_contact_first_name",
"primary_contact_last_name",
"primary_contact_email",
"primary_contact_phone_number",
"primary_contact_phone_type",
"secondary_contact_first_name",
"secondary_contact_last_name",
"secondary_contact_email",
"secondary_contact_phone_number",
"secondary_contact_phone_type",
"address",
]
def create(self,validated_data):
address_data=validated_data.pop("address")
client=Client.objects.create(**validated_data)
Address.objects.create(client=client,**address_data)
return client
example data to post:
{
"primary_contact_first_name": "iliyas",
"primary_contact_last_name": "shaik",
"primary_contact_email": "a#a.com",
"primary_contact_phone_number": "9185213654",
"primary_contact_phone_type": "HOme",
"secondary_contact_first_name": "meraa",
"secondary_contact_last_name": "shaik",
"secondary_contact_email": "z#z.com",
"secondary_contact_phone_number": "8963251470",
"secondary_contact_phone_type": "Mobile",
"address": {
"street_address_line_1": "NTR NAGAR",
"street_address_line_2": "CHOWRASTA",
"city": "KURNOOL",
"state": "ANDHRA",
"zip": 51896352,
"country": "INDIA"
}
}
client_address_id is null when the post request data is serialized and clientaddress_id is foriegn key which should be id of row present in address model table but here no data is being saved ,the address model table is empty.How could I do this?
You need to override create the method of ClientSerializer
class ClientSerializer(serializers.ModelSerializer):
address = AddressSerializer(source="addresss")
class Meta:
model = Client
fields = [
"primary_contact_first_name",
"primary_contact_last_name",
"primary_contact_email",
"primary_contact_phone_number",
"primary_contact_phone_type",
"secondary_contact_first_name",
"secondary_contact_last_name",
"secondary_contact_email",
"secondary_contact_phone_number",
"secondary_contact_phone_type",
"address",
]
def create(self, validated_data):
address_data = validated_data['address']
# Create address instance
address = Address.objects.create(...)
# Create client instance
client = Client.objects.create(...)
return client

Django Foreign Key ["Incorrect type. Expected pk value, received str."]

The Company table has the basic contact information of the company, and the Address contains the address and geolocation of the company. These two tables are connected with a foreign key named "company_name," which is neither a primary key of both tables. I inserted some mock data of a company named "FF2" into the company table, it went great. However, when I attempted to insert "FF2" with its mock address into the Address table, I failed and received this:
company_name: ["Incorrect type. Expected pk value, received str."]
I tried every solution I found online, but none of them worked. Please help and be specific as possible, thank you so much!!
model.py:
class Address(models.Model):
city = models.CharField(max_length=200)
state = models.CharField(max_length=200)
zip = models.CharField(max_length=20)
address1 = models.CharField(max_length=200)
address2 = models.CharField(max_length=200, blank=True, null=True)
company_name = models.ForeignKey('Company', models.DO_NOTHING, db_column='company_name')
lat = models.DecimalField(max_digits=50, decimal_places=6)
long = models.DecimalField(max_digits=50, decimal_places=6)
class Meta:
managed = False
db_table = 'address'
class Company(models.Model):
company_name = models.CharField(unique=True, max_length=200)
contact_name = models.CharField(max_length=100)
phone = models.CharField(max_length=100)
email = models.CharField(max_length=100)
website = models.TextField()
class Meta:
managed = False
db_table = 'company'
views.py:
class AddressView(APIView):
serializer_class = AddressSerializer
def get(self, request):
address = [ {"city": address.city, "state": address.state, "zip": address.zip, "address1": address.address1, "address2": address.address2, "company_name": address.company_name, "lat": address.lat, "long": address.long}
for address in Address.objects.all()]
return Response(address)
def post(self, request):
serializer = AddressSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
class CompanyView(APIView):
serializer_class = CompanySerializer
def get(self, request):
company = [ {"company_name": company.company_name, "contact_name": company.contact_name, "phone": company.phone, "email": company.email, "website": company.website}
for company in Company.objects.all()]
return Response(company)
def post(self, request):
serializer = CompanySerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
return Response(serializer.data)
serializer.py:
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = ['city', 'state', 'zip', 'address1', 'address2', 'company_name', 'lat', 'long']
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ['company_name', 'contact_name', 'phone', 'email', 'website']

Overwrite create method for a Django restframework nested serializer

I am trying to use nested writable serializer in django-rest-framework. When I send a POST request with following data:
{
"acc_name": "Salary Card",
"acc_type_id": {
"id": 2,
"acc_type_name": "Debit Card"
},
"credit_amt": null,
"bill_dt": null,
"due_dt": null,
"balance": "0.00",
"comments": null
}
I got an error:
Cannot assign "OrderedDict([('acc_type_name', 'Debit Card')])": "Accounts.acc_type_id" must be a "AccountTypes" instance.
I actually passed id for AccountTypes, but why restframework remove it automatically? How can I resolve this problem? How can I create a new account with existing account type?
Views:
class AccountTypesViewSet(ListAPIView):
name = __name__
pagination_class = None
queryset = AccountTypes.objects.filter(active='Y')
serializer_class = AccountTypesSerializer
class AccountsViewSet(viewsets.ModelViewSet):
pagination_class = None
queryset = Accounts.objects.all()
serializer_class = AccountsSerializer
Models:
class AccountTypes(models.Model):
id = models.AutoField(primary_key=True, editable=False)
acc_type_name = models.CharField(max_length=50)
active = models.CharField(max_length=1, default='Y')
class Meta:
db_table = f'"{schema}"."taccount_types"'
managed = False
class Accounts(models.Model):
id = models.AutoField(primary_key=True, editable=False)
acc_name = models.CharField(max_length=1024)
acc_type_id = models.ForeignKey(
to=AccountTypes,
db_column='acc_type_id',
related_name='accounts',
on_delete=models.DO_NOTHING
)
credit_amt = models.DecimalField(max_digits=11, decimal_places=2, null=True)
bill_dt = models.DateField(null=True)
due_dt = models.DateField(null=True)
balance = models.DecimalField(max_digits=11, decimal_places=2, default=0)
comments = models.CharField(max_length=1024, null=True)
class Meta:
db_table = f'"{schema}"."taccounts"'
managed = False
Serializers:
class AccountTypesSerializer(serializers.ModelSerializer):
class Meta:
model = AccountTypes
fields = ('id', 'acc_type_name')
class AccountsSerializer(serializers.ModelSerializer):
# acc_type = serializers.SlugRelatedField(slug_field='acc_type_name', source='acc_type_id', read_only=True)
acc_type_id = AccountTypesSerializer()
class Meta:
model = Accounts
fields = ('id', 'acc_name', 'acc_type_id', 'credit_amt',
'bill_dt', 'due_dt', 'balance', 'comments')
def create(self, validated_data):
accounts_instance = Accounts.objects.create(**validated_data)
return accounts_instance
You don't need to set id field because Django will do it by itself, so remove that lines:
id = models.AutoField(primary_key=True, editable=False)
Next, you need to send an id of AccountTypes model to create new account and you give Django a dict fields = ('id', 'acc_type_name'). It doesn't know what to do with that. So just send id as number. And you don't need AccountTypesSerializer and that line acc_type_id = AccountTypesSerializer() also.
Next, you should create account in view, not in serializer, and you have to save it after creating.

Error: expected pk value, received list for foreignkey field

I cannot save multiple values for the Foreignkey field when adding instances to the database. I don't understand exactly what the problem is: in my code or in the format of the JSON object being passed.
models.py
class VendorContacts(models.Model):
contact_id = models.AutoField(primary_key=True)
vendor = models.OneToOneField('Vendors', on_delete=models.CASCADE)
contact_name = models.CharField(max_length=45, blank=True)
phone = models.CharField(max_length=45, blank=True)
email = models.CharField(max_length=80, blank=True, unique=True)
class Meta:
db_table = 'vendor_contacts'
class VendorModuleNames(models.Model):
vendor = models.OneToOneField('Vendors', on_delete=models.CASCADE, primary_key=True)
module = models.ForeignKey(Modules, models.DO_NOTHING)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'vendor_module_names'
unique_together = (('vendor', 'module'),)
class Vendors(models.Model):
COUNTRY_CHOICES = tuple(COUNTRIES)
vendorid = models.AutoField(primary_key=True)
vendor_name = models.CharField(max_length=45, unique=True)
country = models.CharField(max_length=45, choices=COUNTRY_CHOICES)
nda = models.DateField(blank=True, null=True)
user_id = models.ForeignKey('c_users.CustomUser', on_delete=models.PROTECT)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'vendors'
unique_together = (('vendorid', 'timestamp'),)
serializers.py
class VendorsSerializer(serializers.ModelSerializer):
class Meta:
model = Vendors
fields = ('vendor_name',
'country',
'nda',
'parent_vendor',)
class VendorContactSerializer(serializers.ModelSerializer):
class Meta:
model = VendorContacts
fields = (
'contact_name',
'phone',
'email',)
class VendorModulSerializer(serializers.ModelSerializer):
class Meta:
model = VendorModuleNames
fields = ('module',)
views.py
class VendorsCreateView(APIView):
"""Create new vendor instances from form"""
serializer_class = (VendorsSerializer)
def post(self, request, *args, **kwargs):
vendor_serializer = VendorsSerializer(data=request.data)
vendor_contact_serializer = VendorContactSerializer(data=request.data)
vendor_modules_serializer = VendorModulSerializer(data=request.data)
try:
vendor_serializer.is_valid(raise_exception=True) \
and vendor_contact_serializer.is_valid(raise_exception=True) \
and vendor_modules_serializer.is_valid(raise_exception=True) \
vendor = vendor_serializer.save(user_id=request.user)
vendor_contact_serializer.save(vendor=vendor)
vendor_modules_serializer.save(module= maybe something here?????, vendor=vendor)
except ValidationError:
return Response({"errors": (vendor_serializer.errors,
vendor_contact_serializer.errors,
vendor_modules_serializer.errors
)},
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(request.data, status=status.HTTP_200_OK)
JSON body
{
"vendor_name": "Awrazofgsxsdsxjwszsslsasdjegdzasas",
"country": "Canada",
"module": [
1,
2
],
"NDA date": "",
"contact_name": "Tim",
"email": "teaszt#tesstd.gmail",
"phone": "+3464784594940",
"parent_vendor": "23"
}
When I send JSON, I get the response
{
"module": [
"Incorrect type. Expected pk value, received list."
]
}
Looks like I'm finally confused about multiple saving
Your ForeignKey should be set on the related class Modules.

Marshmallow Nested Serializer KeyError: u'Manager'

I'm using Marshmallow's nested serializers and getting the error "KeyError: u'manager'".
Here are my serializers:
class ShiftSerializer(Schema):
agent = fields.String()
date = fields.String()
end = fields.String()
status = fields.String()
class KPIShiftSerializer(Schema):
interval = fields.DateTime()
incoming = fields.Integer()
duration = fields.Decimal()
shifts_future = fields.Nested(ShiftSerializer, many=True)
shifts_current = fields.Nested(ShiftSerializer, many=True)
shifts_ending = fields.Nested(ShiftSerializer, many=True)
And my models:
class Shift(models.Model):
agent = models.CharField(default=" ", max_length=200)
date = models.CharField(default='01/01/1900', max_length=10)
end = models.DateTimeField(default=utc.localize(datetime(1900,1,1)))
status = models.CharField(default='Available', max_length=200)
class KPI(models.Model):
interval = models.DateTimeField(default=timezone.now)
incoming = models.IntegerField(default=0)
duration = models.FloatField(default=0)
shifts_future = models.ManyToManyField(Shift, related_name="returning")
shifts_current = models.ManyToManyField(Shift, related_name="staffed")
shifts_ending = models.ManyToManyField(Shift, related_name="leaving")

Categories