In my Django application I am getting Json like this:
"sales_order": 102,
"transport_by": 4,
I want to expand the sales_order and replace it with it's owner's first_name + last_name.
So I tried using slugrelated field but I am not sure how to get two values out of it.
Here's what I tried:
class AtableSOSerializer(serializers.ModelSerializer):
owner = serializers.SlugRelatedField(read_only=True, slug_field='first_name'+' '+'last_name')
class Meta:
model = MaterialRequest
fields = "__all__"
class AtableFlowListSerializer(serializers.ModelSerializer):
class Meta:
model = AllotmentFlow
fields = "__all__"
class AllotmentTableSerializer(serializers.ModelSerializer):
flows = AtableFlowListSerializer(many=True)
sales_order = AtableSOSerializer(read_only=True)
class Meta:
model = Allotment
fields = "__all__"
But obvious error appeared:
AttributeError: 'User' object has no attribute 'first_name last_name'
How do I get the first_name + last_name in my JSON?
i had same problem as you :
in models.py add a proprety to your model then in your serializer make your slug_field is the proprety you created in your model.
#property
def full_name(self):
return self.first_name+" "+self.last_name
owner = serializers.SlugRelatedField(read_only=True, slug_field='full_name')
Related
I have the following ModelSerializer with a create method. In this method I call the model's update_or_create method. But when I do this, the serializer's validation raises the error
rest_framework.exceptions.ValidationError: [{'non_field_errors': [ErrorDetail(string='The fields user_id, capacity_id must make a unique set.', code='unique')]}, {}].
I thought that since I'm using update_or_create, it would find the row that matches validated data's user_id and capacity_id, and then update that row. But the validation runs before create, and the data is not valid because of the unique constraint. So how do I ignore this constraint?
class ActivatedCapacitySerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(required=False)
capacity_id = serializers.IntegerField(required=False)
class Meta:
model = ActivatedCapacity
fields = ('user_id', 'capacity_id', 'active')
def create(self, validated_data):
activated_capacity = ActivatedCapacity.objects.update_or_create(
user_id=validated_data['user_id'],
capacity_id=validated_data['capacity_id'],
defaults = {
'active': validated_data['active']
}
)
return activated_capacity
Models.py
class ActivatedCapacity(models.Model):
user_id = models.IntegerField()
capacity_id = models.IntegerField()
active = models.BooleanField(default=False)
class Meta:
unique_together = ('user_id', 'capacity_id',)
I just had to include in the serializer's class Meta an empty validators list, so it will override the model's default validators.
class ActivatedCapacitySerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(required=False)
capacity_id = serializers.IntegerField(required=False)
class Meta:
model = ActivatedCapacity
fields = ('user_id', 'capacity_id', 'active')
validators = []
...
I have a model with a one-to-one relationship with a main model:
class User(models.Model):
id = models.BigIntegerField(primary_key=True)
username = models.CharField(max_length=100, blank=True)
class AggregatedStats(models.Model):
user_id = models.ForeignKey('User', on_delete=models.DO_NOTHING, unique=True)
followers_30d = models.BigIntegerField(blank=True)
I have written the following serializers:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'followers']
class AggregatedStatsSerializer(serializers.HyperlinkedModelSerializer):
username = UserSerializer(source='user.username')
class Meta:
model = AggregatedStats
fields = ['followers_30d', 'username']
I am trying to return the username from the User model, but whatever I try to get it, the best I can do is get the hyperlinked related field from user, but not the actual "username" attribute. How would you return this?
You can simply create a field and return it:
class AggregatedStatsSerializer(serializers.HyperlinkedModelSerializer):
username = SerializerMethodField()
class Meta:
model = AggregatedStats
fields = ['followers_30d', 'username']
def get_username(self, obj):
return obj.user_id.username
I have models:
class CommonEditor(models.Model):
def __str__(self):
return 'Common Atributes Mask'
class Color(models.Model):
name = models.CharField(max_length=25)
editor = models.ForeignKey(CommonEditor, on_delete=models.PROTECT, null=True)
So I make serialization this way:
class ColorSerializer(serializers.ModelSerializer):
class Meta:
model = Color
fields = '__all__'
class CommonAttributesSerializer(serializers.ModelSerializer):
color = ColorSerializer(many=True, read_only=True)
class Meta:
model = CommonEditor
fields = ('pk', 'color')
And then view:
class CommonAttributeAPIView(generics.ListCreateAPIView):
serializer_class = CommonAttributesSerializer
queryset = CommonEditor.objects.all()
I get only pk of my CommonEditor Model. Why can't i get the full Atributes Mask and how can I fix it? Big thanks!
Default name for reverse foreign key relation is modelname_set or in your case color_set. So try to rename color field to color_set:
class CommonAttributesSerializer(serializers.ModelSerializer):
color_set = ColorSerializer(many=True, read_only=True)
class Meta:
model = CommonEditor
fields = ('pk', 'color_set')
This can also be achieved via SerializerMethodField and can be seen as follow:
class CommonAttributesSerializer(serializers.ModelSerializer):
color = serializers.SerializerMethodField()
class Meta:
model = CommonEditor
fields = ('pk', 'color')
def get_color(self, common_editor):
return ColorSerializer(common_editor.color_set.all(), many=True).data
Documentation: http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
The CommonAttributesSerializer search for a color attribute in CommonEditor's instance, but it couldn't find. In DRF serializer, a parameter called source will says explicitly where to look for the data. So , change the serializer as below:
class CommonAttributesSerializer(serializers.ModelSerializer):
color = ColorSerializer(many=True, read_only=True, <b>source='color_set'</b>)
class Meta:
model = CommonEditor
fields = ('pk', 'color')
Reference : DRF Fields -source
models.py
class Userinfo(models.Model):
useruid = models.BigAutoField(db_column='UserUID', primary_key=True)
useremail = models.CharField(
db_column='UserEmail', unique=True, max_length=100)
userpassword = models.CharField(db_column='UserPassword', max_length=128)
passwordsalt = models.CharField(db_column='PasswordSalt', max_length=128)
class Meta:
managed = False
db_table = 'userinfo'
class Postinfo(models.Model):
postuid = models.BigAutoField(db_column='PostUID',primary_key=True)
useruid = models.ForeignKey(
'Userinfo', db_column='UserUID', on_delete=models.CASCADE)
content = models.TextField(db_column='Content')
class Meta:
managed = False
db_table = 'postinfo'
if i get userlist and user's last post
i think use annotate
models.Userinfo.objects.all().annotate(lastpost="??").order_by("-useruid")
what values in "??"
like this form
[{userinfo1,"lastpost":{postinfofields}},{userinfo2,"lastpost":{postinfofields}},{userinfo3,"lastpost":{postinfofields}}]
can i this query not use forloop?
Serializer.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Postinfo
fields = ('postuid','content')
class UserSerializer(serializers.ModelSerializer):
lastpost = PostSerializer()
class Meta:
model = Userinfo
fields = ['useruid', 'useremail', 'lastpost']
view.py
userinfos = models.Userinfo.objects.all().order_by("-useruid")
result = UserSerializer(userinfos,many=True)
print(result.data)
raise Exception
Got AttributeError when attempting to get a value for field `lastpost` on serializer `UserSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Userinfo` instance.
Original exception text was: 'Userinfo' object has no attribute 'lastpost'.
if i add read_only=True print this
[OrderedDict([('useuid', 1), ('useremail', 'test')]), OrderedDict([('useruid', 2), ('useremail', 'test2')])]
You can use model's property for this:
class Userinfo(models.Model):
useruid = models.BigAutoField(db_column='UserUID', primary_key=True)
useremail = models.CharField(
db_column='UserEmail', unique=True, max_length=100)
userpassword = models.CharField(db_column='UserPassword', max_length=128)
passwordsalt = models.CharField(db_column='PasswordSalt', max_length=128)
#property
def lastpost(self):
return self.postinfo_set.latest('postuid')
Now you dont need annotation, just use it for example in template like this:
{{ user.lastpost.content }}
UPD
To serialize property with ModelSerializer just add serializer's field 'lastpost':
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Postinfo
fields = ('postuid','content')
class UserSerializer(serializers.ModelSerializer):
lastpost = PostSerializer()
class Meta:
model = Userinfo
fields = ['useruid', 'useremail', 'lastpost']
UPD2
You can also implement logic directly on the serializer level, without model's property. Just use SerializerMethodField:
class UserSerializer(serializers.ModelSerializer):
lastpost = SerializerMethodField()
class Meta:
model = Userinfo
fields = ['useruid', 'useremail', 'lastpost']
def get_lastpos(self, obj):
last = obj.postinfo_set.latest('postuid')
serializer = PostSerializer(last)
return serializer.data
I want to fetch the foreign key values in PUT and GET but while using the many=True I am getting error TypeError object is not iterable.
Here are following the my snippets.
I have two models called MasterStatus and MasterType. In MasterType I have foreign key values of MasterStatus.
models.py
class MasterType(models.Model):
id = models.BigIntegerField(primary_key=True)
type_name = models.CharField(max_length=255, blank=True, null=True)
fk_status = models.ForeignKey(MasterStatus)
def __unicode__(self):
return u'%s' % (self.type_name)
class Meta:
managed = False
db_table = 'master_type'
In serializer I am using the many=True to get the nested values of foreignkey. Here I have used PrimaryKeyRelatedField serializer.
serializer.py
class MasterTypeSerializer(serializers.HyperlinkedModelSerializer):
fk_status = serializers.PrimaryKeyRelatedField(queryset=MasterStatus.objects.all(),many=True)
class Meta:
model = MasterType
fields = ('id', 'type_name', 'fk_status', 'last_modified_date', 'last_modified_by')
depth = 2
ForeignKey links to a single MasterStatus instance, therefore it is not many.
Your serializers should look something like this:
class MasterTypeSerializer(serializers.HyperlinkedModelSerializer):
fk_status = serializers.PrimaryKeyRelatedField(
queryset=MasterStatus.objects.all())
class Meta:
model = MasterRepaymentType
class MasterStatusSerializer(serializers.HyperlinkedModelSerializer):
fk_type = serializers.PrimaryKeyRelatedField(
queryset= MasterRepaymentType.objects.all(), many=True)
class Meta:
model = MasterStatus
Note that many is used on the fk_type field as a MasterStatus has many MasterRepaymentType.
Hope this helps.