Django Rest Framework nested serializer gives attribute error - django

I am trying to setup a nested serializer below I've posted the models and serializer. why am I getting the below error ?
Got AttributeError when attempting to get a value for field `balance_sheet` on serializer `StockSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Stock` instance.
Original exception text was: 'Stock' object has no attribute 'balance_sheet'.
serializers.py
class StockSerializer(serializers.ModelSerializer):
income_statement = IncomeStatementSerializer(many=True)
balance_sheet = BalanceSheetSerializer(many=True)
cashflows_statement = CashflowsStatementSerializer(many=True)
def create(self, validated_data):
temp_income_statement_data = validated_data.pop("income_statement")
temp_balance_sheet_data = validated_data.pop("balance_sheet")
temp_cashflows_statement_data = validated_data.pop("cashflows_statement")
new_stock = Stock.objects.create(**validated_data)
for i in temp_income_statement_data:
IncomeStatement.objects.create(**i, ticker=new_stock)
for x in temp_balance_sheet_data:
BalanceSheet.objects.create(**x, ticker=new_stock)
for y in temp_cashflows_statement_data:
CashflowsStatement.objects.create(**y, ticker=new_stock)
return new_stock
IncomeStatementSerializer, BalanceSheetSerializer and CashflowsStatementSerializer are all typical ModelSerializer's
models.py
class Stock(models.Model):
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
ticker = models.CharField(max_length=10, unique=True, primary_key=True)
slug = models.SlugField(default="", editable=False)
def save(self, *args, **kwargs):
value = self.ticker
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
def __str__(self):
return self.ticker
class Meta:
verbose_name = "stock"
verbose_name_plural = "stocks"
ordering = ["ticker"]
IncomeStatement, BalanceSheet and CashflowsStatement are all typical models.Model with a ForeignKey relationship to Stock
views.py
class StockList(generics.ListCreateAPIView):
queryset = Stock.objects.all()
serializer_class = StockSerializer
lookup_field = "slug"

Related

BooleanField in ModelSerializer

I want to display the content of Trader class through an API call. But I don't know where am I wrong.
models.py
class Trader(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="trader")
bot_status = models.BooleanField(blank=False, default=False)
active_group = models.ManyToManyField(Entry, blank=True, related_name="active_group")
def __str__(self):
return f'{self.user.username}'
def __repr__(self):
return f'Trader=(bot_status={self.bot_status}, active_group={self.active_group})'
serializers.py
class BotStatusSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source = 'user.username')
class Meta:
model = Trader
read_only_fields = ('bot_status', )
views.py
class BotStatusView(viewsets.ModelViewSet):
serializer_class = BotStatusSerializer
def get_queryset(self):
return self.request.user.trader.bot_status
When I make the request I get the following Error.
Error:
return [
TypeError: 'bool' object is not iterable
You are returning bot_status, a boolean, from get_queryset, which needs to return a QuerySet.
def get_queryset(self):
return Trader.objects.filter(trader=self.request.user)

DRF- Got assertion error when I give Post Request

Error
AssertionError: The `.create()` method does not support writable dotted-source fields by default.
Write an explicit `.create()` method for serializer `hrm_apps.configuration.serializers.CurrencySerializer`, or set `read_only=True` on dotted-source serializer fields.
models.py,
class CurrencyMaster(models.Model):
code = models.CharField(max_length=3, null=False, unique=True)
name = models.CharField(max_length=100, null=False, unique=True)
def __str__(self):
return self.name
class Currency(models.Model):
currency_master = models.OneToOneField(CurrencyMaster, on_delete=models.RESTRICT)
conversion_rate = models.FloatField(null=False)
def __str__(self):
return self.currency_master.name
views.py,
class CurrencyViewSet(viewsets.ModelViewSet):
queryset = Currency.objects.all()
serializer_class = CurrencySerializer
lookup_field = 'id'
serializers.py,
class CurrencySerializer(serializers.ModelSerializer):
currency_master = serializers.CharField(source="currency_master.name")
class Meta:
model = Currency
fields = ['id', 'currency_master', 'conversion_rate']
When i give post request i got assertion error like above,
class CurrencySerializer(serializers.ModelSerializer):
currency_master = serializers.CharField(source="currency_master.name")
class Meta:
model = Currency
fields = ['id', 'currency_master', 'conversion_rate']
def create(self, validated_data):
return Currency.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.currency_master = validated_data.get('currency_master', instance.currency_master)
instance.conversion_rate = validated_data.get('conversion_rate', instance.conversion_rate)
return instance
I tried above i got this error "ValueError: Cannot assign "{'name': 'ALL - Albania Lek'}": "Currency.currency_master" must be a "CurrencyMaster" instance". How to resolve this???
Customize the create method.
class CurrencySerializer(serializers.ModelSerializer):
currency_master = serializers.CharField(source="currency_master.name")
class Meta:
model = Currency
fields = ['id', 'currency_master', 'conversion_rate']
def create(self, validated_data):
currency_master_name = validated_data.pop('currency_master')["name"]
currency_master_obj = get_object_or_404(CurrencyMaster, name=currency_master_name)
validated_data["currency_master"] = currency_master_obj
return Currency.objects.create(**validated_data)

DRF: How to insert data in another model class on deleting on model class

I am trying to insert data on one modal class on destroying another model class. My First model class:
class UserDevice(models.Model):
type = models.ForeignKey(
'Device',
on_delete=models.CASCADE
)
hardware_serial = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
class NewDevice(models.Model):
type = models.ForeignKey(
'Device',
on_delete = models.CASCADE
)
hardware_serial = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
Whenever I will destroy the UserDevice I want to the same device should be added in NewDevice
My serializer class is :
class UserDeviceSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserSensorDevice
fields = '__all__'
read_only_fields = ['id','created_at']
def create(self, validated_data):
app_id = models.UserDevice.objects.filter(sensor_code= validated_data.get('hardware_serial', None)).first()
if app_id:
msg = _('Application ID is already registered')
raise serializers.ValidationError(msg, code='authorization')
else :
return models.UserDevice.objects.create(**validated_data)
class NewDeviceSerializer(serializers.ModelSerializer):
class Meta:
model = models.NewDevice
fields = '__all__'
read_only_fields = ['id','created_at']
My view class:
class UserSensorRemoveDevice(generics.DestroyAPIView):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
queryset = models.UserDevice.objects.all()
serializer_class = serializers.UserDeviceSerializer
What I have tried to override UserDevice destroy. But somehow its not working:
def destroy(self, validated_data):
return models.NewDevice.objects.create(type = validated_data.get('type', None),hardware_serial = validated_data.get('hardware_serial', None))
Any help will be highly appreciated. Thanks in advance.
You can override UserDevice.delete() method
class UserDevice(models.Model):
...
def delete(self, *args, **kwargs):
NewDevice.objects.create(type=self.type, hardware_serial=self.hardware_serial)
super().delete(*args, **kwargs)
in can just override your model UserDevice delete function
def delete(self, using=None, keep_parents=False):
#add new NewDevice instance
super().delete(using, keep_parents,*args,**kwargs)

Django Restful Api of ManytoMany models to show the foreign objects

The "Brand" object is foreign key of "company",they are ManytoMany relationship,and Brand object exists the field "company_Group"
the models are as follows:
class Brand(models.Model):
Company_Group = models.ManyToManyField(Company)
Brand_Group = models.CharField(u'Brand Group',max_length=255, default="")
Pref_Brand_Name_Flg = models.CharField(u'Preferred Name Flag',max_length=255, default="")
Pref_Brand_Name = models.CharField(u'Preferred Name',max_length=255, default="")
PrimaryContact = models.ForeignKey(UserRole, null=True, blank=True)
class Company(models.Model):
Pref_Company_Name_Flg = models.CharField(u'Preferred Name Flag',max_length=255, default="")
Pref_Company_Name = models.CharField(u'Preferred Name',max_length=255, default="")
Company_Type = models.CharField(u'Company Type',max_length=255, default="")
serializers
class BrandSerializer(serializers.ModelSerializer):
class Meta:
model = Brand
fields = '__all__'
the Serializer as follows ,data_export_setting.Company_form_stand is the field as
class CompanySerializer(serializers.HyperlinkedModelSerializer):
Brand = BrandSerializer(source='brand', read_only=True)
class Meta:
model = Company
Company_form_stand=['id', 'Brand', 'Company_Type','Company_Name','company_Name_SC']
fields = data_export_setting.Company_form_stand
depth = 2
def create(self, validated_data):
return Company.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.__dict__.update(**validated_data)
instance.save()
return instance
the viewset are as follows
class BrandViewSet(viewsets.ModelViewSet):
queryset = Brand.objects.all()
serializer_class = BrandSerializer
model = Brand
def get_serializer(self, *args, **kwargs):
if 'data' in kwargs:
data = kwargs['data']
if isinstance(data, list):
kwargs['many'] = True
return super(BrandViewSet, self).get_serializer(*args, **kwargs)
class CompanyViewSet(viewsets.ModelViewSet):
queryset = Company.objects.all()
serializer_class = CompanySerializer
and I want to show the company objects with Brand objects ,however,it seems to ignore the brand object and its field
appreciate any help ,thanks
Try,
Brand = BrandSerializer(source='brand_set', read_only=True, many=True)
Since, you have defined the field relation as ManyToMany, more than one Brand objects are related to a single Company instance. By using the reverse relation, you can access them in your serializer, and many=True lets the serializer handle multiple objects in the relation.

Could not resolve URL for hyperlinked relationship using view name "place-info".

I search a lot for this problem but no any solution work for me. I am get Could not resolve URL for hyperlinked relationship using view name "place-info". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field. when I want to access this resource through my API in django.
I am getting error like this:
Could not resolve URL for hyperlinked relationship using view name "place-info". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
My model is ass follows:
class TourSite(models.Model):
"""Destination place"""
place_name = models.CharField(max_length=100, blank=False, default='')
place_address = models.CharField(max_length=200, blank=False, default='')
place_image = models.ImageField(upload_to="TourSite", blank=True)
def get_place_name(self):
return self.place_name
def get_place_address(self):
return self.place_address
def save(self, *args, **kwargs):
super(TourSite, self).save(*args, **kwargs)
def __str__(self):
return self.place_name
class Info(models.Model):
"""Stores information about the place."""
place_name = models.OneToOneField(
TourSite,
on_delete = models.CASCADE,
primary_key = True,
)
famous_for = models.CharField(max_length=200, blank=True, default='')
brief_info = models.TextField(blank=True, default='')
def get_famous_for(self):
return self.famous_for
def get_brief_info(self):
return self.brief_info
def get_place_name(self):
return self.place_name
def save(self, *args, **kwargs):
super(Info, self).save(*args, **kwargs)
def __str__(self):
return "%s is famous for %s"% (self.place_name, self.famous_for)
My Serailizer :
class InfoSerializer(serializers.ModelSerializer):
class Meta:
model = Info
fields = '__all__'
class TourSiteSerializer(serializers.HyperlinkedModelSerializer):
place_info = serializers.HyperlinkedIdentityField(view_name='place-info')
class Meta:
model = TourSite
fields = ('id', 'place_name','place_info', 'place_address', 'place_image')
My views:
#api_view(['GET'])
def api_root(request):
return Response({
'places': reverse('places-list', request=request),
})
class TourSiteList(DefaultsMixin, generics.ListAPIView):
queryset = TourSite.objects.all()
search_fields = ("place_name", "place_address", )
serializer_class = TourSiteSerializer
class TourSiteDetail(DefaultsMixin, generics.RetrieveUpdateDestroyAPIView):
queryset = TourSite.objects.all()
serializer_class = TourSiteSerializer
class Info(generics.ListAPIView):
queryset = Info.objects.all()
serializer_class = InfoSerializer
My urls
urlpatterns = [
url(r'^$', views.api_root),
url(r'^places/$', views.TourSiteList.as_view(), name="places-list"),
url(r'^places/(?P<pk>[0-9]+)/$', views.TourSiteDetail.as_view(), name="places-detail"),
url(r'^info/$', views.Info.as_view(), name='place-info'),
]
How can I resolve this issue?
Since I can't comment:
Your class Meta classes have the wrong indentation. They should be indented inside of their appropriate classes. If it is just a transcription error then it should be fixed for the question.
I had a similar situation involving HyperlinkedRelatedField on a OneToOneField that was a model's primary key.
Ended up needing to specify both the lookup_field and the lookup_url_kwarg arguments for HyperlinkedRelatedField.
Here is what this solution would look like applied to your serializer:
class TourSiteSerializer(serializers.HyperlinkedModelSerializer):
place_info = serializers.HyperlinkedIdentityField(
view_name='place-info',
lookup_field='place_info_id', # <-- note the `_id` suffix
lookup_url_kwarg='place_info',
)
class Meta:
model = TourSite
fields = ('id', 'place_name','place_info', 'place_address', 'place_image')