DRF- Got assertion error when I give Post Request - django

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)

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)

Django Rest Framework nested serializer gives attribute error

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"

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)

The `.create()` method does not support writable nested fields by default

I am new to Django REST, I was trying to make some entry to the DB using the serilaizer in django rest. But i am getting some errors while using the create method.
My models are,
class CoreInformation(models.Model):
site_name = models.CharField(max_length=145, blank=True, null=True)
status = models.CharField(max_length=45, blank=True, null=True)
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
class Meta:
managed = False
db_table = 'core_information'
class CoreDetailInformation(models.Model):
core_info = models.ForeignKey('CoreInformation', models.DO_NOTHING, related_name='core_base_info')
old_sac = models.CharField(max_length=45, blank=True, null=True)
msc = models.CharField(max_length=45, blank=True, null=True)
class Meta:
db_table = 'core_detail_information'
And i have two ModelSerializer like below ,
class CoreDetailSerializer(serializers.ModelSerializer):
class Meta:
model = CoreDetailInformation
fields = ('id','old_sac', 'msc')
class CustomCoreInfoSerializer(serializers.ModelSerializer):
core_base_info = CoreDetailSerializer(many=True)
class Meta:
model = CoreInformation
# fields = '__all__'
fields = ('id', 'site_name', 'status', 'created_at', 'core_base_info')
#transaction.atomic
def create(self, validated_data):
try:
with transaction.atomic():
base_info = CoreInformation.objects.create(site_name=validated_data['site_name'],status=validated_data['status']
for site_detail in validated_data['core_base_info']:
CoreDetailInformation.objects.get_or_create(msc=site_detail['msc'],old_sac=site_detail['old_sac'],core_info=base_info)
except CoreInformation.DoesNotExist as e:
raise e
except CoreDetailInformation.DoesNotExist as e:
raise e
and my views.py is ,
class CoreInformation(generics.ListCreateAPIView):
queryset = models.CoreInformation.objects.all()
serializer_class = CustomCoreInfoSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = self.perform_create(serializer)
serializer = self.get_serializer(instance=instance)
return Response(serializer.data, status=status.HTTP_201_CREATED)
def perform_create(self, serializer):
return serializer.create(validated_data=serializer.validated_data)
To create the CoreInformation my input will be like below,
{
"site_name": "xxxxxxxxxx",
"status": "create",
"core_base_info": [{
"old_sac": '1',
"msc": "abc1,abc2"
},
{
"old_sac": '2',
"msc": "abc3,abc4"
}]
}
But when i am compiling its returns me the below error,
AssertionError at /api/core/
The `.create()` method does not support writable nested fields by default.
Write an explicit `.create()` method for serializer `src.core.serializers.CustomCoreInfoSerializer`, or set `read_only=True` on nested serializer fields.
I found this , but did n't help for me.
Any help would be greatly appreciated. Thanks.
I think that you can use this GitHub to solve your problem
Try this: https://github.com/beda-software/drf-writable-nested

Trouble POSTing multiple related objects at once to api created with django rest framework

I'm making a ToDo app but having difficulties getting the api to allow a user to create a new list with multiple items via one api call. Each list belongs to a specific "room".
I get 400 Bad Request. If I leave the 'todo_items' off the POST data it works fine to create the ToDoList object.
Also, if I remove "user" from the Meta fields attribute for the CreateToDoItemSerializer, it'll create both the ToDoList object and the ToDoItem objects, but the "content" for each ToDoItem will be an empty string. Inside the create method of NewToDoListSerializer, the validated_data is returning a list of empty OrderedDict() objects for the key "todo_items". I'm not sure what to make of that.
my models:
class Room(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
slug = models.SlugField(max_length=255, blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="rooms")
class ToDoList(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, blank=True)
room = models.ForeignKey(Room, related_name="todo_lists")
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="todo_lists")
class ToDoItem(models.Model):
todo_list = models.ForeignKey(ToDoList, related_name="todo_items")
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="replies")
content = FroalaField(options={'placeholder': '''Just start writing...
Highlight any text to bring up the editor.'''})
my serializers
class CreateTodoItemSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(many=False, read_only=False, queryset=User.objects.all())
class Meta:
model = ToDoItem
fields = ['pk', 'user', 'content']
def create(self, validated_data):
reply = ToDo.objects.create(**validated_data)
class NewToDoListSerializer(serializers.ModelSerializer):
room = serializers.PrimaryKeyRelatedField(many=False, read_only=False, queryset=Room.objects.all())
user = UserSerializer(read_only=True)
todo_items = CreateTodoItemSerializer(many=True, read_only=False)
class Meta:
model = ToDoList
fields = ['pk', 'slug', 'title', 'user', 'room', 'todo_items']
lookup_field = "slug"
depth = 1
def create(self, validated_data):
todo_items_data = validated_data.pop('todo_items')
todo_list = ToDoList.objects.create(**validated_data)
for todo_item_data in todo_items_data:
todo_item = ToDo.objects.create(user=todo_list.user, todo_list=todo_list, **todo_item_data)
my viewset (the relevant bits):
class ToDoListViewSet(viewsets.ModelViewSet):
queryset = ToDoList.objects.all()
serializer_class = ToDoListSerializer
authentication_classes = [TokenAuthentication, SessionAuthentication]
permission_classes = [IsAuthenticated]
renderer_classes = (renderers.TemplateHTMLRenderer, renderers.JSONRenderer, renderers.BrowsableAPIRenderer)
template_name = "react_base.html"
lookup_field = "slug"
def create(self, request, **kwargs):
self.serializer_class = NewToDoListSerializer
return super(ToDoListViewSet, self).create(request, **kwargs)
def perform_create(self, serializer):
instance = serializer.save(user=self.request.user)
the data I'm POSTing:
todoListTitle, todoItemContent, moreTodoItemContent are all strings. this.props.room.pk is an integer. this.props.csrfmiddlewaretoken is the csrfmiddlewaretoken
var newToDoListData = {
"room": this.props.room.pk,
"title": todoListTitle,
"todo_items": [{"content": todoItemContent}, {"content": moreTodoItemContent}],
"csrfmiddlewaretoken": this.props.csrfmiddlewaretoken
};
You need to make the todo_items in your serializer required = false. I am not sure I understand what your second issue is.
class NewToDoListSerializer(serializers.ModelSerializer):
room = serializers.PrimaryKeyRelatedField(many=False, read_only=False, queryset=Room.objects.all())
user = UserSerializer(read_only=True)
todo_items = CreateTodoItemSerializer(many=True, required=False)
class Meta:
model = ToDoList
fields = ['pk', 'slug', 'title', 'user', 'room', 'todo_items']
lookup_field = "slug"
depth = 1
def create(self, validated_data):
todo_items_data = validated_data.pop('todo_items')
todo_list = ToDoList.objects.create(**validated_data)
for todo_item_data in todo_items_data:
todo_item = ToDo.objects.create(user=todo_list.user, todo_list=todo_list, **todo_item_data)