How do you display fields from a related model in admin.py? - django

I have the following models:
class Property(models.Model):
user = models.ForeignKey(User)
id = models.CharField(max_length=20, null=True)
class Property_Value(models.Model):
id = models.ForeignKey(Property)
amount = models.DecimalField(max_digits = 10, decimal_places
How do I access the Property_Value.amount via Property on the admin page?
I have this so far...
class PropertyAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'property_value')
def property_value(self, obj):
return obj.id.amount
class Meta:
model = Property
admin.site.register(Property, PropertyAdmin)

You're interacting, in that instance, with a Property object (since you defined that in the Meta) - syntax is the same as elsewhere in Django. So it would be obj.property_value.amount. If you're using PyCharm, you can get autocomplete for the field by telling PyCharm what 'obj' is, like so:
def property_value(self, obj: Property):

Related

Adding a custom, non-model attribute to query set in Django?

Newbie to DRF and have a model called posts. And another called user. The post object looks as follows:
class Post(models.Model):
"""
Post model
"""
title = models.CharField(max_length=250)
body = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='forum_posts')
parent_post = models.ForeignKey('self',
on_delete=models.CASCADE,
blank=True,
null=True)
time_stamp = models.DateTimeField(default=timezone.now)
objects = models.Manager()
The serializer for this model is:
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = models.Post
fields = ('id', 'title', 'body', 'parent_post', 'author', 'time_stamp')
extra_kwargs = {'id': {'read_only': True},
'author': {'read_only': True}}
When returning data for this model, I want to add an extra attribute to each object within the query set called "author_username". The username should be the username belonging to the post's author id. I also want to do this without modifying the model to add another attribute such as "author_username" since this'll be redundant (already have an FK for author). So, ideally, the json for an object would look like:
'post_id': 1
'post_title': 'Example post'
'post_body': 'Example post'
'author_id': 1
'parent_post_id': null
'time_stamp': '2022'
'author_username': 'testUser'
How can I go about doing this?
Here's my view:
class PostList(generics.ListCreateAPIView):
permission_classes = [IsAuthenticatedOrReadOnly]
queryset = models.Post.objects.all()
serializer_class = serializers.PostSerializer
The source argument can be passed to a serializer field to access an attribute from a related model
class PostSerializer(serializers.ModelSerializer):
author_username = serializers.CharField(source="author.username", read_only=True)
class Meta:
model = models.Post
...
You should add a select_related call to your view's queryset
class PostList(generics.ListCreateAPIView):
...
queryset = models.Post.objects.select_related('author')
...

Property field not appearing in django serializer

I have a property inside a Django model, I have to show it inside the serializer. I put the field inside the serializer, but it's not coming up in the response.
class Example(models.Model):
field_1 = models.ForeignKey(
Modelabc, on_delete=models.CASCADE, null=True, related_name="abc"
)
field_2 = models.ForeignKey(
Modelxyz,
on_delete=models.CASCADE,
null=True,
related_name="xyz",
)
name = models.CharField(max_length=25, blank=True)
#property
def fullname(self):
if self.name is not None:
return "%s%s%s" % (self.field_1.name, self.field_2.name, self.name)
return "%s%s" % (self.field_1.name, self.field_2.name)
Serializer is like this:
class ExampleSerializer(serializers.ModelSerializer):
fullname = serializers.ReadonlyField()
class Meta:
model = Example
fields = [
"id",
"fullname",]
When I call the get API for this, the fullname is not being displayed in the api response. What is the issue?
#property attributes are not included in Django Serializer fields as only Django model fields are shown. I normally use the following workaround for this.
Create a SerializerMethodField.
Return object.property from the method.
So, your Serializer class would be:
class ExampleSerializer(serializers.ModelSerializer):
fullname = serializers.SerializerMethodField()
class Meta:
model = OnlineClass
fields = [
"id",
"fullname",
]
def get_fullname(self, object):
return object.fullname
I think, in ExampleSerializer class, the model should be Example not OnlineClass and the fields should contain all the fields inside the model.

Django Rest Framework Serializer - return related field

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

Can't render nested relationship in Django Rest Framework

The problem is I have a 'details' field which should render into a nested relationship with it's parent serializer. I have tried a bunch of stuff and nothing seems to be working.
Here's my models:
class BusinessOrderModel(OrderToModel):
reference = models.IntegerField()
business_num = models.ForeignKey('BusinessModel', on_delete=models.CASCADE)
def __str__(self):
return str(self.reference)
class BusinessModel(models.Model):
Business_num = models.IntegerField(primary_key=True)
def __str__(self):
return str(self.Business_num)
class DetailModel(models.Model):
id = models.AutoField(primary_key=True)
detail = models.TextField()
order = models.ForeignKey('BusinessOrderModel', on_delete=models.CASCADE)
and here's my serializers which aren't working:
class DetailSerializer(serializers.ModelSerializer):
class Meta:
model = DetailModel
fields = ('id', 'detail')
class BusinessOrderSerializer(serializers.ModelSerializer):
details = DetailSerializer(many=True)
class Meta:
model = BusinessOrderModel
fields = ('reference', 'business_num', 'details')
I've tried many different things but I get this error:
Got AttributeError when attempting to get a value for field details
on serializer BusinessOrderSerializer. The serializer field might be
named incorrectly and not match any attribute or key on the
BusinessOrderModel instance. Original exception text was:
'BusinessOrderModel' object has no attribute 'details'.
Any help is much appreciated.
Thank you very much.
Using details to lookup reverse relationships only works if you set it as the related_name. The default for BusinessOrderModel to DetailModel will be detailmodel_set.
To make it accessible by calling details you should make this change:
class DetailModel(models.Model):
id = models.AutoField(primary_key=True)
detail = models.TextField()
order = models.ForeignKey('BusinessOrderModel', related_name="details", on_delete=models.CASCADE)
Now you can use DetailModel.objects.get(id=1).details.all()
You can also customize the query in your serializer:
class BusinessOrderSerializer(serializers.ModelSerializer):
details = SerializerMethodField()
class Meta:
model = BusinessOrderModel
fields = ('reference', 'business_num', 'details')
def get_details(self, obj):
return DetailSerializer(obj.details.filter(), many=True).data

Multiple slug_field in SlugRelatedField Django Rest Framework

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')