DRF PUT request on unique model field - django

I have the following model:
class Movie(models.Model):
name = models.CharField(max_length=800, unique=True)
imdb_rating = models.IntegerField(null=True)
movie_choice = (
('Act', 'Action'),
...........
)
movie_type = models.CharField(max_length=3, choices=movie_choice)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Hiren(models.Model):
movie = models.ForeignKey(Movie)
watched_full = models.BooleanField(default=True)
rating = models.IntegerField()
source = models.CharField(max_length=500, null=True)
watched_at = models.DateField()
quality_choice = (
..................
)
video_quality = models.CharField(max_length=3, choices=quality_choice)
created_at = models.DateField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
and serializer:
class MovieSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
fields = '__all__'
class HirenSerializer(serializers.ModelSerializer):
movie = MovieSerializer()
class Meta:
model = Hiren
fields = ('movie', 'id', 'watched_full', 'rating', 'source', 'video_quality', 'watched_at')
def update(self, instance, validated_data):
instance.movie.name = validated_data.get('movie', {}).get('name')
instance.movie.imdb_rating = validated_data.get('movie', {}).get('imdb_rating')
instance.movie.movie_type = validated_data.get('movie', {}).get('movie_type')
instance.watched_full = validated_data.get('watched_full', instance.watched_full)
instance.rating = validated_data.get('rating', instance.rating)
instance.source = validated_data.get('source', instance.source)
instance.video_quality = validated_data.get('video_quality', instance.video_quality)
instance.watched_at = validated_data.get('watched_at', instance.watched_at)
instance.movie.save()
instance.save()
return instance
When I try to send a put request without changing name field from Movie model it throws an error
{
"movie": {
"name": [
"movie with this name already exists."
]
}
}
However, I can perfectly update any other field if I change the name field's value each time.

The problem is in Movie model defined by you.
When you set the name field of Movie model as unique = True,then any new entry with same movie name will always throw an error.
In your model,
class Movie(models.Model):
name = models.CharField(max_length=800, unique=True)
imdb_rating = models.IntegerField(null=True)
movie_choice = (
('Act', 'Action'),
...........
)
movie_type = models.CharField(max_length=3, choices=movie_choice)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
If you want to add two entries with the same name,remove the line unique = True or make sure to save every entry with a different name.
Or,if you want to update the record/entry then you don't need to assign a value for name field,just remove that line from your code,alternatively check if the name of the movie is already same with an improvement in the code like this :
class HirenSerializer(serializers.ModelSerializer):
movie = MovieSerializer()
class Meta:
model = Hiren
fields = ('movie', 'id', 'watched_full', 'rating', 'source', 'video_quality', 'watched_at')
def update(self, instance, validated_data):
movie_name = validated_data.get('movie', {}).get('name')
if movie_name != instance.movie.name :
instance.movie.name = movie_name
instance.movie.imdb_rating = validated_data.get('movie', {}).get('imdb_rating')
instance.movie.movie_type = validated_data.get('movie', {}).get('movie_type')
instance.watched_full = validated_data.get('watched_full', instance.watched_full)
instance.rating = validated_data.get('rating', instance.rating)
instance.source = validated_data.get('source', instance.source)
instance.video_quality = validated_data.get('video_quality', instance.video_quality)
instance.watched_at = validated_data.get('watched_at', instance.watched_at)
instance.save()
return instance
Hope this helps,Thanks.

Related

Cannot assign "'user_name'": "Class.user" must be a "Account_class" instance

enter image descripI am getting this error when I try to make a post requesttion here
How to can I solve this problem?
Here is my model:
class Coffee(models.Model):
name = models.CharField(max_length=60)
ratings = models.CharField(max_length=5)
taste = models.TextField()
coffeeType = models.CharField(max_length=60)
price = models.CharField(max_length=60)
img = models.CharField(max_length=200)
updated_at = models.DateTimeField(auto_now_add=True)
shopName = models.CharField(max_length=60)
coffeeShopID = models.CharField(max_length=200)
location = models.CharField(max_length=200)
user = models.ForeignKey(Account, on_delete=models.CASCADE, null=False, blank=False, related_name='user')
def __str__(self):
return self.name[0:50]
class Meta:
ordering = ['-updated_at']
Here is the serializer of that model:
class CoffeeSerializers(serializers.ModelSerializer):
class Meta:
model = Coffee
fields = '__all__'
Here is views for post request:
def addCoffee(request):
data = request.data
coffee = Coffee.objects.create(
name=data['name'],
ratings=data['ratings'],
taste=data['taste'],
coffeeType=data['coffeeType'],
price=data['price'],
img=data['img'],
shopName=data['shopName'],
coffeeShopID=data['coffeeShopID'],
location=data['location'],
user=data['user']
)
coffee.save()
serializer = CoffeeSerializers(coffee)
return Response(serializer.data)
i can only assume how your Account model looks like, problem is that you must send Account model, but you are sending string data['user']
def addCoffee(request):
data = request.data
account_object = Account.objects.get(THIS_IS_ACCOUNT_NAME = data['user'])
coffee = Coffee.objects.create(
name=data['name'],
ratings=data['ratings'],
taste=data['taste'],
coffeeType=data['coffeeType'],
price=data['price'],
img=data['img'],
shopName=data['shopName'],
coffeeShopID=data['coffeeShopID'],
location=data['location'],
user=account_object
)
coffee.save()
serializer = CoffeeSerializers(coffee)
return Response(serializer.data)

How to add nested field after creating the ModelSerializer? Not in the class

Basically i want to have fk_inventory as a nested field in StorageRackSerializer but as you guys can see I also need to use StorageRackSerializer in InventorySerializer.
How can i set the field after creating the serializer class?
I have tried creating a fk_inventory field and set it to None and tried to set to InventorySerializer afterwards but didn't work.
class Inventory(models.Model):
inventory_id = models.AutoField(primary_key=True)
fk_building = models.OneToOneField(Store, on_delete=models.CASCADE, unique=True, related_name='inventory')
def __str__(self):
return f"{self.inventory_id}"
class StorageRack(models.Model):
storage_rack_id = models.AutoField(primary_key=True)
quantity = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(50)])
fk_inventory = models.ForeignKey(Inventory, on_delete=models.CASCADE, related_name="storage_racks")
fk_product_id = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, related_name="storage_racks")
def __str__(self):
return f"{self.storage_rack_id}"
class StorageRackSerializer(serializers.ModelSerializer):
fk_product_id = ProductSerializer(read_only=True)
fk_inventory = None
class Meta:
model = StorageRack
fields = ('storage_rack_id', 'quantity', 'fk_inventory', 'fk_product_id')
class InventorySerializer(serializers.ModelSerializer):
fk_building = StoreSerializer()
storage_racks = StorageRackSerializer(many=True)
class Meta:
model = Inventory
fields = ('inventory_id', 'fk_building', 'storage_racks')
StorageRackSerializer.fk_inventory = InventorySerializer()
You can add a field 'fk_inventory' in the validated data from SorageRackSerializer
validated_data = StorageRackSerializer(data=data)
validated_data['fk_inventory'] = InventorySerializer().data

Get a list of all the field values from a Foreign Key Table in Django

am new to Django and currently trying the Foreign Key concept. I have three models as shown below.
class Basket(models.Model):
basket_name = models.CharField(max_length=5, unique=True)
def __str__(self):
return self.basket_name
class Product(models.Model):
Grams = 'GM'
Kilograms = 'KG'
WeightBased = 'WPG'
QuantityBased = 'CPG'
PRODUCT_UNIT_WT_CHOICES=[
(Grams, 'Grams'),
(Kilograms, 'Kilograms')
]
PRODUCT_TYPE_CHOICES =[
(WeightBased, 'Weight Based Product'),
(QuantityBased, 'Quantity Based Product')
]
product_name = models.CharField(max_length=30, unique=True)
product_description = models.TextField(max_length=300)
product_price = models.DecimalField(max_digits=5, decimal_places=2)
product_unit_weight = models.DecimalField(max_digits=5, decimal_places=2)
product_unit_weight_units = models.CharField(max_length=2, choices=PRODUCT_UNIT_WT_CHOICES, default=Grams)
product_type = models.CharField(max_length=3, choices=PRODUCT_TYPE_CHOICES, default=QuantityBased)
product_image = models.ImageField(upload_to=imageUploadPath, null=True, blank=True)
def __str__(self):
return self.product_name
class BasketProductMapping(models.Model):
basket_reference = models.ForeignKey(Basket, on_delete=models.CASCADE)
product_reference = models.ForeignKey(Product, on_delete=models.CASCADE)
mapped_basket_name = models.CharField(max_length=5,null=False, blank=False)
mapped_product_name = models.CharField(max_length=30, null=False, blank=False)
Here are my serializers:
class ProductSerializer(serializers.ModelSerializer):
product = serializers.CharField(read_only=True)
class Meta:
model = Product
fields = ['id', 'product_name', 'product_description', 'product_price', 'product_unit_weight',
'product_unit_weight_units', 'product_type', 'product_image']
class BasketSerializer(serializers.ModelSerializer):
basket = serializers.CharField(read_only=True)
class Meta:
model = Basket
fields = ('id', 'basket_name')
class BasketProductMappingSerializer(serializers.ModelSerializer):
basket_reference = serializers.CharField(source ='basket.basket_name', read_only=True)
product_reference = serializers.CharField(source='product.product_name', read_only=True)
class Meta:
model = BasketProductMapping
fields = ['id', 'basket_reference', 'product_reference', 'mapped_basket_name', 'mapped_product_name']
What I am trying to achieve is get a list of all the values in 'basket_name' and 'product_name' when I call the BasketProductMappingSerializer. But the output I am getting is this:
{
"status": 1,
"message": "Basket Product Mapping List",
"data": [
{
"id": 1,
"mapped_basket_name": "A1",
"mapped_product_name": "XYZ"
}
]
}
This is my views.py code:
class BasketProductViewSet(APIView):
def get(self, request):
if request.GET.get('id'):
print('Basket Product Mapping Details')
basketProductMappingData = BasketProductMapping.get(id = request.GET.get('id'))
serializer = BasketProductMappingSerializer(basketProductMappingData)
else:
basketProductMappingData = BasketProductMapping.objects.all().values('id', 'basket_reference__basket_name', 'product_reference__product_name', 'mapped_basket_name', 'mapped_product_name')
serializer = BasketProductMappingSerializer(basketProductMappingData, many=True)
response = {'status':1, 'message':"Basket Product Mapping List", 'data':serializer.data}
Where am I going wrong? Sorry if my question is very trivial. Thanks for your help in advance.
i see that there is an error in your views BasketProductMapping.get(id = request.GET.get('id')) should be BasketProductMapping.objects.get(id = request.GET.get('id'))
i don't know if it gonna work but can you try
basket_reference = serializers.ReadOnlyField(source ='basket.basket_name')
product_reference = serializers.ReadOnlyField(source='product.product_name')
instead of
basket_reference = serializers.CharField(source ='basket.basket_name', read_only=True)
product_reference = serializers.CharField(source='product.product_name', read_only=True)

KeyError Post DjangoRestFramework

I'm new on Django Rest Framework and when I want to POST data I get a error: KeyError: 'id_area' I do not know what I'm doing wrong. Here's my code:
in my models.py
class Area(models.Model):
id_area = models.AutoField(primary_key=True)
APM = 'apm'
BUSINESS = 'business'
DESARROLLO = 'desarrollo'
SISTEMAS = 'sistemas'
ATENTUSIANOS_CHOICES = (
(APM, 'Apm'),
(BUSINESS, 'Business'),
(DESARROLLO, 'Desarrollo'),
(SISTEMAS, 'Sistemas'),
)
nombre = models.CharField(max_length=255, choices=ATENTUSIANOS_CHOICES)
class Meta:
verbose_name = 'Área'
verbose_name_plural = 'Áreas'
def __str__(self):
return self.nombre
class Atentusiano(models.Model):
id_atentusiano = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=255, blank=False, null=False)
apellido = models.CharField(max_length=255, blank=False, null=False)
correo = models.CharField(max_length=255, blank=False, null=False, unique=True)
anexo = models.CharField(max_length=255, blank=True, null=True)
area = models.ForeignKey(Area, related_name='areas', on_delete=models.CASCADE)
class Meta:
verbose_name = 'Atentusiano'
verbose_name_plural = 'Atentusianos'
ordering = ['nombre']
def __str__(self):
return self.nombre + ' ' + self.apellido
in my serializers.py
class AreaSerializer(serializers.ModelSerializer):
areas = serializers.CharField(read_only=True)
class Meta:
model = Area
fields = ('id_area', 'nombre', 'areas')
class AtentusianoSerializer(serializers.ModelSerializer):
atentusianos = serializers.CharField(read_only=True)
area = serializers.CharField(source='area.nombre', read_only=True)
id_area = serializers.CharField(source='area.id_area')
class Meta:
model = Atentusiano
fields = ['id_atentusiano', 'nombre', 'apellido', 'correo', 'anexo', 'id_area', 'area', 'atentusianos']
def create(self, validated_data):
area_data = validated_data.pop('id_area')
area = models.Area.objects.create(**area_data)
atentusiano = models.Atentusiano.objects.create(area=area, **validated_data)
return atentusiano
And in my views.py
class AtentusianoView(viewsets.ModelViewSet):
queryset = Atentusiano.objects.all()
serializer_class = AtentusianoSerializer
class AreaView(viewsets.ModelViewSet):
queryset = Area.objects.all()
serializer_class = AreaSerializer
The problem is that when I want to Post data, for example:
{
"nombre": "name",
"apellido": "lastname",
"correo": "email#gmail.com",
"anexo": "1364",
"id_area": "1"
}
i got this error area_data = validated_data.pop('id_area')
KeyError: 'id_area'
I need help please
you should pop like this,
class AtentusianoSerializer(serializers.ModelSerializer):
.....
.....
class Meta:
model = Atentusiano
fields = ['id_atentusiano', 'nombre', 'apellido', 'correo', 'anexo', 'id_area', 'area', 'atentusianos']
def create(self, validated_data):
id_area = validated_data.pop('area')['id_area'] # here the correction
area = Area.objects.create(id_area=id_area) # an additional correction
atentusiano = Atentusiano.objects.create(area=area, **validated_data)
return atentusiano
EDIT: As id_area value, you are passing a string instead of an integer which will through another error. Also not,
area = models.Area.objects.create(**area_data)
it should be,
area = Area.objects.create(id_area=id_area)

How to serialize an object instance which gets the data from 2 separate models using Django Rest Framework?

Query :
I have a GET request which gives the data from the 2 models (single_tracklog_object in View). However, when I serialize this object instance using the serializers I am getting an empty data for devices as below.
{
"lat": "51.0038",
"lon": "8.0038",
"speed": 50,
"course": 5,
"device": {} # this needs to be having a value but is empty.
}
I am not understanding why its happening. Please guide me on this.
My Models :
class Tracklogs(models.Model):
tracklog_id = models.AutoField(primary_key=True)
device = models.ForeignKey(Tracking_devices, related_name='tracklogs')
lat = models.CharField(max_length=10, null=False)
lon = models.CharField(max_length=11, null=False)
.........
#timestamps
tracker_datetime = models.DateTimeField(blank=True, null=True)
class Meta:
get_latest_by = "tracker_datetime"
class Tracking_devices(models.Model):
device_id = models.AutoField(primary_key=True)
device_type = models.ForeignKey(Device_type)
user = models.ForeignKey(User, null=False)
name = models.CharField(max_length=100)
description = models.CharField(max_length=256, blank=True, null=True)
My View :
serializer_class = ShowLocationInfoSerializer
def get(self, request, *args, **kwargs):
# get the imei from the url
imei = self.kwargs['imei']
try:
single_tracklog_object = Tracklogs.objects.filter(device__imei = imei).values('lat', 'lon','speed','course','device','device__name').latest()
# Here its causing problem!!!
serializer = self.serializer_class(single_tracklog_object)
return Response(serializer.data)
except ObjectDoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
My Serializer:
class Tracking_DeviceSerializer(serializers.ModelSerializer):
name = serializers.CharField(read_only=True)
class Meta:
model = Tracking_devices
fields = ('name')
class ShowLocationInfoSerializer(serializers.ModelSerializer):
lat = serializers.CharField(read_only=True)
lon = serializers.CharField(read_only=True)
speed = serializers.IntegerField(read_only=True)
course = serializers.FloatField(read_only=True)
device = Tracking_DeviceSerializer()
class Meta:
model = Tracklogs
fields = ('lat', 'lon', 'tracker_datetime', 'speed', 'course', 'device' )
Thanks in advance.