model
class Enrollee(TimeStampedModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, verbose_name=_('id'))
first_name = models.CharField(max_length=60, verbose_name=_('first name'))
dependents = models.ManyToManyField(to=Dependant, blank=True, verbose_name=_('dependents'))
class Dependant(TimeStampedModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, verbose_name=_('id'))
first_name = models.CharField(max_length=60, verbose_name=_('first name'))
view
class EnrolleeViewSet(viewsets.ModelViewSet):
queryset = models.Enrollee.objects.all()
serializer_class = serializers.EnrolleeSerializer
filter_class = filters.EnrolleeFilter
serializers
class EnrolleeSerializer(DynamicFieldsMixin, DynamicFieldsModelSerializer):
dependents = DependantSerializer(many=True, required=False)
def create(self, validated_data):
dependant_data = validated_data.pop('dependents')
enrollee = models.Enrollee.objects.create(**validated_data)
for dependant in dependant_data:
models.Dependant.objects.create(**dependant)
return enrollee
class Meta:
model = models.Enrollee
fields = '__all__'
error:
{
"first_name": "hmo1",
"dependents": [],
}
It means dependents is not inserting
Here I am trying to send nested data for my dependents(ManyToManyField)
But, Getting above error while inserting data.
Is there any way we can achive this ?
{
"first_name":"soubhagya",
"dependents" : [
{
"first_name":"soubhagya"
}
]
}
Above is the data i am sending using post method.
please have a look
def create(self, validated_data):
dependant_data = validated_data.pop('dependents')
enrollee = models.Enrollee.objects.create(**validated_data)
for dependant in dependant_data:
obj = models.Dependant.objects.create(**dependant)
enrollee.dependents.add(obj)
enrollee.save()
return enrollee
Related
I'm writing app in witch I store data in separate models. Now I need to combine this data to use it.
The problem.
I have three models:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=50, blank=True)
...
class Contacts(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
contact_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="contact_user")
class UserPhoto(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
url = models.CharField(max_length=220)
How can I get the current user contacts with their names and pictures like this (serialized)
{
{
"contact_user":"1",
"first_name":"Mark ",
"url":first picture that corresponds to contact_user id
},
{
"contact_user":"2",
"first_name":"The Rock",
"url":first picture that corresponds to contact_user id
}
}
Now I'm quering the Contacts model to get all contacts_user id's that he has connection to.
class MatchesSerializer(serializers.ModelSerializer):
class Meta:
model = Contacts
fields = '__all__'
depth = 1
class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactsSerializer
def get_queryset(self):
return Contacts.objects.filter(user__id=self.request.user.id)
The thing you need to is to serialize the Contacts queryset to include the related User and UserPhoto objects for each contact.
Try to create a custom serializer for the Contacts model so:
class ContactSerializer(serializers.ModelSerializer):
contact_user = serializers.SerializerMethodField()
def get_contact_user(self, obj):
user = obj.contact_user
photo = user.userphoto_set.first()
return {
"id": user.id,
"first_name": user.first_name,
"url": photo.url if photo else None
}
class Meta:
model = Contacts
fields = ("contact_user",)
Then, modify the ContactViewSet to use this newly created serializer so:
class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactSerializer
def get_queryset(self):
return Contacts.objects.filter(user__id=self.request.user.id)
Note: Generally, Django models don't require s to be added as suffix since it is by default added, so it is better to modify it as Contact from Contacts.
I'm working on a small project using Django Rest Framework, I have two models ( contacts and category)
So a contact can be in a category, I have a foreign key between the models, I would like to know how can I get data category name instead of getting the id number.
This is my code :
class Category(models.Model):
cat_name = models.CharField(blank=False, max_length=255)
comment = models.CharField(blank=False, max_length=255)
private = models.BooleanField(default=False)
allowed = models.BooleanField(default=False)
def __str__(self):
return self.name
class Contact(models.Model):
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING)
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
My serializer
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = "__all__"
Result I get :
"first_name": "John",
"last_name": "Doe",
"category": 1 ( i want to get the name of the category instead of the id )
This is one possible solution
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = "__all__"
def to_representation(self, obj):
return {
"first_name": obj.first_name,
"last_name": obj.last_name,
"category": obj.category.cat_name
}
Try this:
class ContactSerializer(serializers.ModelSerializer):
category_name = serializers.SerializerMethodField('get_category_name')
def get_category_name(self, obj):
if obj.category_id:
return obj.category.cat_name
return ""
class Meta:
model = Contact
fields = "__all__"
I got into same situation.I think there is no need to write another function if you can achieve this by one line of code and adding it to fields using source.You can also try this:
class ContactSerializer(serializers.ModelSerializer):
category = serializers.CharField(source="category.cat_name", read_only=True)
class Meta:
model = Contact
fields = ['first_name','last_name', 'category']
I want to customize the django rest framework serializer return object to a specific requirement. right now it returns the fields in a single object that is not nested.
{
"id": 9,
"namespace": "steve",
"path": "something/another",
"value": "this is a value"
},
and this is what I want the outcome to look like:
{
"id": 6,
"namespace": "tempnamespaced",
"path": "randompath",
"value": "anothertest",
"user": {
"userId": "testUser1"
}
}
So i want to add a nested object named user and add the userID value within the user.
the data that is returned in the userId is actually person.username
person is a model username so the data is going to look like this when it is assigned and returned:
"user": {
"userId": {{person.username}}
}
I will attach mmy code below:
serializer:
from rest_framework import serializers
from .models import Preference
from django.contrib.auth.models import User
class PreferenceSerializer(serializers.ModelSerializer):
# person = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(),)
class Meta:
model = Preference
fields = ('id', 'namespace', 'path', 'value')
here is the get viewset:
#permission_classes((IsAuthenticated))
def get_queryset(self):
namespace = self.kwargs.get('namespace', None)
path = self.kwargs.get('path', None)
if namespace is None and path is None:
queryset = Preference.objects.all().filter(user_id=1)
if namespace and path is None:
queryset = Preference.objects.all().filter(user_id=1, namespace=namespace)
if namespace and path:
queryset = Preference.objects.all().filter(user_id=1, namespace=namespace, path=path)
return queryset
here is the mode:
from django.db import models
from django.contrib.auth.models import User
from owf_framework.people.models import Person
class Preference(models.Model):
id = models.BigAutoField(primary_key=True, null=False)
version = models.BigIntegerField(default=1, null=False)
path = models.CharField(max_length=200, null=False)
namespace = models.CharField(max_length=200, null=False)
value = models.TextField(null=False)
user_id = models.BigIntegerField(null=False, default=1)
person = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.namespace
class Meta:
db_table = 'preference'
Define to_representation() in your serializer:
class PreferenceSerializer(serializers.ModelSerializer):
# person = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(),)
class Meta:
model = Preference
fields = ('id', 'namespace', 'path', 'value')
def to_representation(self, instance):
ret = super().to_representation(instance)
ret['user'] = {'userId': instance.person.username}
return ret
You can add a method to your model to return the username instead of the field name.
class Preference(models.Model):
id = models.BigAutoField(primary_key=True, null=False)
version = models.BigIntegerField(default=1, null=False)
path = models.CharField(max_length=200, null=False)
namespace = models.CharField(max_length=200, null=False)
value = models.TextField(null=False)
user_id = models.BigIntegerField(null=False, default=1)
person = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.namespace
def get_username(self):
return self.person.username
class Meta:
db_table = 'preference'
The Serializer can now use this method.
class PreferenceSerializer(serializers.ModelSerializer):
person = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(),)
class Meta:
model = Preference
fields = ('id', 'namespace', 'path', 'value', 'person', 'get_username')
I am trying to create an api for device group and device. A device group can have multiple devices and i want to have the post api for device group with multiple devices because group creation is shown only when device is selected and user might select multiple devices and then create a new group. That way when group is created, those selected devices should also be shown as device_list
Here is my code, i am not sure on how to do post request
class BaseDevice(PolymorphicModel):
name = models.CharField(max_length=250, blank=False, null=False)
group = models.ForeignKey('DeviceGroup', related_name="groups", null=True, blank=True)
class Device(BaseDevice):
description = models.TextField(blank=True, null=True)
class DeviceGroup(models.Model):
name = models.CharField(max_length=250, blank=False, null=False)
class DeviceIdSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = Device
# id is the token of the device and name is the name of the device
fields = ('id', 'name')
class DeviceGroupSerializer(serializers.ModelSerializer):
name = serializers.StringRelatedField()
device_list = DeviceIdSerializer(read_only=False, many=True, required=False, source="groups")
class Meta:
model = DeviceGroup
# name is the name of group created and device_list is the list of devices with id(token) and device name
fields = ('id', 'name', 'device_list')
def create(self, validated_data):
print ('validated_data', validated_data)
device_list_data = validated_data.pop('device_list')
group = DeviceGroup.objects.create(**validated_data)
for device_list in device_list_data:
BaseDevice.objects.create(group=group, **device_list)
return group
class DeviceGroupAPIView(APIView):
permission_classes = (permissions.IsAuthenticated,)
def get_object(self, user, token):
try:
return BaseDevice.objects.filter(owner=user).get(token=token)
except ObjectDoesNotExist:
return error.RequestedResourceNotFound().as_response()
def post(self, request, token=None, format=None):
device_group_instance = DeviceGroup.objects.get(token=token)
for device_token in request.data['devices']:
device = Device.objects.get(token=device_token, owner=request.user)
device.group = device_group_instance
Here is my api design
{
"data":[
{
"id":1,
"name":"Home",
"device_list":[
{
"id":"481cfef5a4884e52a63d135967fbc367",
"name":"Oxygen Provider"
},
{
"id":"7eb006d6db50479aa47f887da0d4f10e",
"name":"Fan Speed"
}
]
},
{
"id":2,
"name":"Business",
"device_list":[
]
}
]
}
UPDATE
url(r'^device_group/(?P<token>[0-9a-f]+)/add$', DeviceGroupAPIView.as_view(), name='device_group'),
I've changed your code a bit
class BaseDevice(PolymorphicModel):
name = models.CharField(max_length=250, blank=False, null=False)
group = models.ForeignKey('DeviceGroup', related_name="groups", null=True, blank=True)
class Device(BaseDevice):
description = models.TextField(blank=True, null=True)
class DeviceGroup(models.Model):
name = models.CharField(max_length=250, blank=False, null=False)
class DeviceIdSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
# token does not exist in your model so this will not be included
class Meta:
model = Device
# id is the token of the device and name is the name of the device
fields = ('id', 'name')
class DeviceGroupSerializer(serializers.ModelSerializer):
device_list = DeviceIdSerializer(read_only=False, many=True, required=False, source="groups")
class Meta:
model = DeviceGroup
# name is the name of group created and device_list is the list of devices with id(token) and device name
fields = ('id', 'name', 'device_list')
def create(self, validated_data):
print ('validated_data', validated_data)
device_list_data = validated_data.pop('groups', [])
# notice that I pop 'groups' because validation changes the input data
# to match the field names
# Also since it is not required I've added a default value
group = DeviceGroup.objects.create(**validated_data)
devices = [BaseDevice(group=group, **device_list) for device_list in device_list_data]
BaseDevice.objects.bulk_create(devices)
# Use bulk create when you have to create multiple objects
# It hits the db only once instead of multiple times
return group
class DeviceGroupAPIView(ModelViewSet):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = DeviceGroupSerializer
queryset = DeviceGroup.objects.all()
# Although I have used ModelViewSet, you could use any other one
# I used this so that I don't need to write the code for create,
# update, delete or list
# urls.py
router = routers.DefaultRouter()
router.register(r'device_group', DeviceGroupAPIView, base_name='device_group')
# this gives the following urls
# /device_group/ POST to create, GET to list
# /device_group/(?<pk>\d+)/ GET to retrieve single DeviceGroup, PATCH/PUT to update it, and DELETE to delete it
This is the structure of the JSON to POST to create a new DeviceGroup with a bunch of Devices
{
"name":"Group Name",
"device_list":[
{
"name":"Device 1"
},
{
"name":"Device 2"
},
{
"name":"Device 3"
}
]
}
Hope this helps
Also you should read up more about Django-Rest-Framework
I am creating an api where the list of groups are shown along with the devices id that falls under that groups. For example if there is a device named Speedometer, Humidifier and they fall under Home group then my api should include
{
"id": 1,
"name": "Home"
"device_list": [
{
"id": "b45c56ioxa1"
},
{
"id": "h4oc2d5ofa9"
}
]
},
but my code does not produce device_list in the api. It only shows name and id
device_list is the list of all the devices id that are in a certain group.
Here is my code
class DeviceIdSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = Device
fields = ('id')
class DeviceGroupSerializer(serializers.ModelSerializer):
name = serializers.StringRelatedField()
device_list = DeviceIdSerializer(read_only=False, many=True, required=False, source="groups")
class Meta:
model = DeviceGroup
fields = ('id', 'name', 'device_list')
class DevicesGroupsAPIView(APIView):
permission_classes = (permissions.IsAuthenticated,)
def get(self, request, format=None):
"""
Returns a list of groups
"""
reply = {}
try:
groups = DeviceGroup.objects.all()
print ('reply', groups)
reply['data'] = DeviceGroupSerializer(groups, many=True).data
except:
reply['data'] = []
return Response(reply, status.HTTP_200_OK)
class BaseDevice(PolymorphicModel):
# User's own identifier of the product
name = models.CharField(max_length=250, blank=False, null=False)
# Any device should have a owner, right from the creation
owner = models.ForeignKey(User, blank=False, null=False)
token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
group = models.ForeignKey('DeviceGroup', related_name="groups", null=True, blank=True)
class Device(BaseDevice):
description = models.TextField(blank=True, null=True)
class DeviceGroup(models.Model):
name = models.CharField(max_length=250, blank=False, null=False)
I tried out the very same code you have except I used models.Model as the base model.
The first time I got an error
The fields option must be a list or tuple or "all". Got str.
which clearly states where your problem is.
So I changed class the fields option in DeviceIdSerializer
DeviceIdSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = Device
fields = ('id',)
Note that I've added a comma (",") which makes fields a tuple instead of a string as it was before.
Now the data I get is
{
"id":1,
"name":"test",
"device_list":[
{
"id":"38ec7e152f9d49a38008c859a1022525"
},
{
"id":"b0d799509260474cb092899ef84ce49c"
},
{
"id":"e5c7cf8f9f5043c68c34c7b962569b08"
}
]
}
which is the same as what you are looking for...
I think your serializers need to look like this:
class DeviceIdSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = Device
fields = ('id')
class DeviceGroupSerializer(serializers.ModelSerializer):
name = serializers.StringRelatedField()
groups = DeviceIdSerializer(read_only=False, many=True, required=False)
class Meta:
model = DeviceGroup
fields = ('id', 'name', 'groups')
Or change this:
class BaseDevice(PolymorphicModel):
# User's own identifier of the product
name = models.CharField(max_length=250, blank=False, null=False)
# Any device should have a owner, right from the creation
owner = models.ForeignKey(User, blank=False, null=False)
token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
group = models.ForeignKey('DeviceGroup', related_name="device_list", null=True, blank=True)