Serializers not displaying foreign key data - django

My serializers are not showing related Models. I mean the models that have got many-to-one relationship. Please see the code below. Forgive my English.
Completely confusing me please help. I am new to django. I am trying to save my Draft js ContentState to the database. I have made the Post model a Foreignkey to my Block models. But When I try to retrieve the data using django-rest-framework serializers the blocks are not displaying.
Same applies with the Blocks I tried to serialize them on their own but the inlineStyleRanges and entityRanges data is not coming up.
#models.py
class Post(models.Model):
created_by= models.ForeignKey(User, on_delete=models.CASCADE)
cat= models.ForeignKey(Category, on_delete=models.CASCADE)
class Block(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
key = models.CharField(max_length=255)
text = models.TextField()
type = models.CharField(max_length=90)
depth = models.IntegerField(default=0)
class InlineStyleRange(models.Model):
block = models.ForeignKey(Block, on_delete=models.CASCADE)
offset = models.IntegerField()
length = models.IntegerField()
style = models.CharField(max_length=90)
class EntityRange(models.Model):
block = models.ForeignKey(Block, on_delete=models.CASCADE)
offset = models.IntegerField()
length = models.IntegerField()
key = models.IntegerField()
class Data(models.Model):
data = models.TextField()
class EntityRangeData(Data):
enityrange = models.ForeignKey(EntityRange, on_delete=models.CASCADE)
#Entity map here we go
class EntityEntry(models.Model):
key = models.IntegerField()
block= models.ForeignKey(Block, on_delete=models.CASCADE)
type = models.CharField(max_length=90)
mutability = models.CharField(max_length=90)
class EntityEntryData(Data):
entityentry = models.ForeignKey(EntityEntry, on_delete=models.CASCADE)
```#Serializers.py```
class EntityEntryDataSerializer(serializers.ModelSerializer):
class Meta:
model = models.EntityEntryData
fields = "__all__"
class EntityEntrySerializer(serializers.ModelSerializer):
data = EntityEntryDataSerializer()
class Meta:
model = models.EntityEntry
fields = "__all__"
class EntityRangeDataSerializer(serializers.ModelSerializer):
class Meta:
model = models.EntityRangeData
fields = "__all__"
class EntityRangeSerializer(serializers.ModelSerializer):
data = EntityRangeDataSerializer()
class Meta:
model = models.EntityRange
fields = "__all__"
class InlineStyleRangeSerializer(serializers.ModelSerializer):
class Meta:
model = models.InlineStyleRange
fields = "__all__"
class BlockSerializer(serializers.ModelSerializer):
inlineStyleRanges = InlineStyleRangeSerializer(many=True, required=False)
entityRanges = EntityRangeSerializer(many=True, required=False)
class Meta:
model = models.Block
fields = "__all__"
class PostSerializer(serializers.ModelSerializer):
blocks = BlockSerializer(many=True, required=False, read_only=True)
class Meta:
model = models.Post
fields = "__all__"
The output be like
[
{
"id": 1,
"created_by": 1,
"cat": 2
}
]

The Block model does not have attributes called inlineStyleRanges or entityRanges, so you should either use related_name in the ForeignKey field or you could specify a source argument in the serializer.
inlineStyleRanges = InlineStyleRangeSerializer(many=True, required=False, source='inlinestyle_set')
entityRanges = EntityRangeSerializer(many=True, required=False, source='entityrange_set')
You might have to include both nested serializers in BlockSerializer.Meta.fields as well. Instead of "__all__", use a list:
fields = ['id', 'post', 'key', 'inlineStyleRanges', 'entityRanges']

Related

fields in class Meta got invalid

models.py
class Product(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(decimal_places=5,max_digits= 1500)
summary = models.TextField()
featured = models.BooleanField()
def __str__(self):
return self.title
# return f'product title:{self.title}-product price:{self.price}'workok
class Meta:
ordering = ('-price',)
class Opinion(models.Model):
name = models.CharField(max_length=20)
email = models.EmailField(max_length=20)
body = models.TextField()
opinion_date = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=False)
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='opinion_set')
def __str__(self):
return f'({self.name}) add opinion about ({self.product})'
forms.py:
from django.forms import ModelForm
from .models import Product #space after from keyword
class OpinionModelForm(ModelForm):
class Meta:
model = Product
fields = ['name','email','body','product']
invalid in code line :
fields = ['name','email','body','product'] #---- NOT WORK !!!
, but if i change above code to :
fields = "__all__" # ----it is WORKing ok without any problem !!
question : what is the error? I am not need all the fields in the Product model (like active boolean field), I need only 'name','email','body','product' fields .
According to the error and the code you provided the main problem is that you made a mistake in chosing model in serializer:
class OpinionModelForm(ModelForm):
class Meta:
model = Product
fields = ['name','email','body','product']
Serializer name is OpinionModelForm and listed fields belong to Opinion so I guess you actually wanted to serialize Opinion and no Product as you defined at this line:
model = Product
Simply change it to:
model = Opinion

Django Creating constraints on serializers

I'm trying to extend Django's Poll app. Each poll will have 2 choices and either an image for each choice or a color for each choice, but not both. My models look like this:
class Question(models.Model):
question = models.CharField()
created_at = models.DateTimeField(auto_now_add=True)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice = models.CharField(max_length=120)
vote_count = models.IntegerField(default=0)
class ChoiceImage(models.Model):
choice = models.OneToOneField(Choice, on_delete=models.CASCADE)
img = models.ImageField()
class ChoiceColor(models.Model):
choice = models.OneToOneField(Choice, on_delete=models.CASCADE)
color = models.CharField(max_length=7)
I have a View that looks like this:
class CreateQuestionView(CreateAPIView):
serializer_class = CreateQuestionSerializer
With the following serializers:
class ChoiceImageSerializer(serializers.ModelSerializer):
class Meta:
model = ChoiceImage
fields = ('image',)
class ChoiceColorSerializer(serializers.ModelSerializer):
class Meta:
model = ChoiceColor
fields = ('color',)
class ChoiceSerializer(serializers.ModelSerializer):
choice_image = ChoiceImageSerializer(many=False)
choice_color = ChoiceColorSerializer(many=False)
class Meta:
model = Choice
fields = ('choice', 'choice_image', 'choice_color')
class CreateQuestionSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True)
class Meta:
model = Question
fields = ('question', 'choices')
How do I create this constraint on my serializers? Also Am I designing this efficiently or is there a better way to do this?

How to serialize a self recursive many-to-many model using a through table in django rest_framework?

i am developing a rest API using django rest framework and i am stuck at a serializer the idea is to serialize a self recursive many to many model using a through table my code is:
model.py:
class Patient(models.Model):
class Meta:
db_table = 'patients'
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
id_card = models.CharField(max_length=45)
dob = models.DateField()
gender = EnumChoiceField(enum_class=Gender)
patientscol = models.CharField(max_length=45)
fk_user = models.ForeignKey(Users, related_name='user_patient', on_delete=models.CASCADE)
relative = models.ManyToManyField("self", through='PatientHasRelative')
class PatientHasRelative(models.Model):
class Meta:
db_table = 'patients_has_relatives'
fk_patient = models.ForeignKey(Patient, related_name='patient_has', on_delete=models.CASCADE)
fk_relative_patient = models.ForeignKey(Patient, related_name='patient_relative', on_delete=models.CASCADE)
relationship = EnumChoiceField(enum_class=Relationship)
my serializer.py is:
class PatientSerializer(serializers.ModelSerializer):
class Meta:
model = Patient
fields = ('__all__')
id = serializers.UUIDField(read_only=True)
id_card = serializers.CharField(required=True, max_length=45)
dob = serializers.DateField(required=True)
gender = EnumChoiceField(enum_class=Gender)
fk_user = serializers.PrimaryKeyRelatedField(required=True, queryset=Users.objects.all())
relative = PatientSerializer(read_only=True, required=True)#problem is here i cant use PatientSerializer here
class PatientHasRelativeSerializer(serializers.ModelSerializer):
class Meta:
model = PatientHasRelative
fields = ('__all__')
fk_patient = serializers.PrimaryKeyRelatedField(required=True, queryset=Patient.objects.all())
fk_relative_patient = serializers.PrimaryKeyRelatedField(required=True, queryset=Patient.objects.all())
relationship = EnumChoiceField(enum_class=Relationship)
a little help would be appreciated
To accomplish this you need to define related_name in the source model on the source field ie add
class Patient(models.Model):
relatives = models.ManyToManyField(
"self", through='PatientHasRelative', related_name='patients')
with this related_name you can easily access -- add/delete/set relatives/patients on either side of the relationships in the serializers
You can either do this using intermediary model
relative = Patient(**key_value_fields)
patient = Patient(**key_value_field)
PatientHasRelative.objects.create(
relative=relative, patient=patient, through_defaults=(relationship ='value',))
or you can do this
relative.patients.add(patient, through_defaults=relationship ='value')
or this
patient.relatives.add(relative, through_defaults=relationship ='value')
example retrieving
patient.relatives.all()

DRF, update a single field in nested serializer

these are my models:
class ADS(models.Model):
advertiser = models.ForeignKey(User)
campaign = models.ForeignKey(Campaign, related_name="ads")
headline = models.CharField(max_length=50)
description_1 = models.TextField(blank=True)
description_2 = models.TextField(blank=True)
display_url = models.URLField(blank=True)
final_url = models.URLField(blank=True)
mobile_url = models.URLField(blank=True)
class Meta:
db_table = "ads"
and:
class AdsImages(models.Model):
ads = models.ForeignKey(ADS,blank=True, null=True)
image = models.ImageField(upload_to='images/',default='media/None/no-img.jpg')
class Meta:
db_table = "ads_images"
I have a nested serializer, as you can see the second model is a table with images, so I am uploading asynchronously the images via AngularJs. As you can see the ForeignKey(ADS, blank=True, null=True), so I am not filling it for the first time. My question is that how to update after that the ads field.
here are my serializers:
class AdsImagesSerializer(serializers.ModelSerializer):
image = serializers.ImageField(use_url=True,allow_empty_file=True)
class Meta:
model = AdsImages
fields = ('id','image','ads',)
class ADSerializer(serializers.ModelSerializer):
adsImages = AdsImagesSerializer(many=True)
class Meta:
model = ADS
fields = ('headline','description_1','description_2','display_url','final_url','mobile_url','advertiser','adsImages',)
Partial updates
By default, serializers must be passed values for all required fields or they will raise validation errors. You can use the partial argument in order to allow partial updates
# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

How to use a model field for multiple models in Django Rest Framework

I have a model BstUserActionLog with a foreign key to Django model User. I have another model for user profile information, BstUserProfile. When I do serialize BstUserActionLog with ModelSerializer I do have Django User info serialized as it is supposed to be. But I also need to add BstUserProfile serialized using the same user_id used for User model.
How can I serialize BstUserActionLog with model User and BstUserProfile are both serialized?
From my models.py:
class BstUserActionLog(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User)
bst_action_type = models.ForeignKey(BstActionType)
action_date = models.DateTimeField(auto_now_add=True)
bst_book = models.ForeignKey(BstBook)
new_value_id = models.IntegerField(blank=True, null=True)
old_value_id = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'bst_user_action_log'
class BstUserProfile(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, unique=True)
website = models.CharField(max_length=200)
picture = models.CharField(max_length=100)
is_avatar_uploaded = models.BooleanField(default=False)
is_cover_uploaded = models.BooleanField(default=False)
class Meta:
managed = False
db_table = 'bst_user_profile'
app_label = 'bst'
From my serializers.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','username',)
class BstUserActionLogSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = BstUserActionLog
fields = ('id', 'user', 'bst_action_type', 'action_date', 'bst_book', 'new_value_id', 'old_value_id')
depth = 3
The key to my solution is SerializerMethodField. With this a new field can be added which is calculated with a method. This method signature contains the object to be serialized. After that a regular method serializer is used to return the serialized object.
From my serializers.py
class BstUserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = BstUserProfile
fields = ('is_avatar_uploaded', 'is_cover_uploaded')
class BstUserActionLogSerializer(serializers.ModelSerializer):
user = UserSerializer()
user_profile = serializers.SerializerMethodField()
def get_user_profile(self, obj):
try:
user_profile = BstUserProfile.objects.get(user_id=obj.user_id)
return BstUserProfileSerializer(user_profile).data
except Exception as e:
return {}
class Meta:
model = BstUserActionLog
fields = ('id', 'user', 'user_profile', 'bst_action_type', 'action_date', 'bst_book', 'new_value_id', 'old_value_id')
depth = 3