I try to serialize and save following json
{
"start": "2017-12-12",
"end": "2017-12-12",
"has_refund": false,
"room": {
"key": 0
},
"reserved_days": [ {
"date": "2017-12-12",
"price": "2",
"paymentMethod": "3"
},
{
"date": "2017-12-13",
"price": "2",
"paymentMethod": "3"
}
],
"check_in_time": "14:00",
"check_out_time": "12:00",
"guest_name": "Ivan",
"payed": false
}
SERIALIZERS
class DaySerializer(serializers.ModelSerializer):
class Meta:
model = Day
fields = [
'date',
'price',
'paymentMethod',
]
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = [
'key',
]
class ReservationSerializer(serializers.ModelSerializer):
room = RoomSerializer()
reserved_days = DaySerializer(many=True)
class Meta:
model = Reservation
fields = [
'start',
'end',
'check_in_time',
'check_out_time',
'reserved_days',
'room',
'has_refund',
'payed',
'guest_name',
'reservation_number',
]
def create(self, validated_data):
day_data = validated_data.pop('reserved_days')
room = validated_data.pop('room')
reservation = Reservation.objects.create(**validated_data)
existing_room = Room.objects.get(key=room['key'])
reservation.room = existing_room
reservation.save()
for day in day_data:
day, created = Day.objects.get_or_create(date=day['date'], price=day['price'], paymentMethod=day['paymentMethod'])
reservation.reserved_days.add(day)
return reservation
MODEL
class Day(models.Model):
date = models.DateField(auto_now=False, auto_now_add=False)
price = models.FloatField()
paymentMethod = models.CharField(max_length = 200)
def __unicode__(self):
return str(self.date)
class Room(models.Model):
name = models.CharField(max_length = 200, null=True)
key = models.AutoField(primary_key=True)
def __unicode__(self):
return self.name
class Reservation(models.Model):
start = models.DateField(verbose_name='Заезд', auto_now=False, auto_now_add=False, blank=False)
end = models.DateField(verbose_name='Выезд', auto_now=False, auto_now_add=False, blank=False)
check_in_time = models.TimeField(verbose_name='Время заезда', blank=False)
check_out_time = models.TimeField(verbose_name='Время выезда', blank=False)
has_refund = models.BooleanField(verbose_name='Возвратная бронь', default=True)
payed = models.BooleanField(verbose_name='Оплачено', default=False)
room = models.ForeignKey(Room, null=True, blank=True, verbose_name='Номер', on_delete=models.CASCADE)
reserved_days = models.ManyToManyField(Day, blank=False)
guest_name = models.CharField(verbose_name='Имя гостя', max_length=200, blank=True)
reservation_number = models.CharField(verbose_name='Номер брони', max_length=200, blank=True)
In response I get 500 error and this
KeyError at /core/create/
'key'
However, if I change field of room to name (inside room serializer and create method of reservation serializer), everything works perfectly
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = [
'name',
]
class ReservationSerializer(serializers.ModelSerializer):
room = RoomSerializer()
reserved_days = DaySerializer(many=True)
class Meta:
model = Reservation
fields = [
'start',
'end',
'check_in_time',
'check_out_time',
'reserved_days',
'room',
'has_refund',
'payed',
'guest_name',
'reservation_number',
]
def create(self, validated_data):
day_data = validated_data.pop('reserved_days')
room = validated_data.pop('room')
reservation = Reservation.objects.create(**validated_data)
existing_room = Room.objects.get(name=room['name'])
reservation.room = existing_room
reservation.save()
for day in day_data:
day, created = Day.objects.get_or_create(date=day['date'], price=day['price'], paymentMethod=day['paymentMethod'])
reservation.reserved_days.add(day)
return reservation
Seems that it works only with strings.
How to make it work with number ? The same thing happened with me when I tried saving with pk instead of separated int fieled
Related
models.py
class Client(models.Model):
client_id = models.AutoField(unique=True, primary_key=True)
org = models.ForeignKey(Organisation, on_delete=models.CASCADE, related_name='org',null=True)
product = models.ManyToManyField(Product,related_name='product')
client_name = models.CharField(max_length=100)
client_code = models.CharField(max_length=20)
client_logo = models.ImageField(upload_to=upload_to,storage=DownloadableS3Boto3Storage, null=True, blank=True)
currency = MoneyField(max_digits=10, decimal_places=2, default_currency='INR', null=True)
billing_method = models.CharField(max_length=40)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
email_id = models.EmailField(max_length=100)
contact_no = models.CharField(max_length=20)
mobile_no = models.CharField(max_length=20)
description = models.TextField(max_length=500)
street_address = models.CharField(max_length=250)
city = models.CharField(max_length=50)
state = models.CharField(max_length=50)
country = models.CharField(max_length=50)
pincode = models.CharField(max_length=10)
industry = models.CharField(max_length=100)
company_size = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.IntegerField(default=0, choices=STATUS_CHOICES)
class Meta:
db_table = "client_master"
def __str__(self):
return self.client_name
serializers.py
class Client_Serializers(serializers.ModelSerializer):
#product_name = Product_Serializers(many=True)
product = Product_Serializers(many=True)
class Meta:
model = Client
fields = ('client_id','currency','billing_method','first_name','last_name','description','street_address','city','state','country','pincode','industry','company_size','client_name', 'contact_no','mobile_no', 'email_id','client_logo','client_code','product',)
def create(self, validated_data):
products_data = validated_data.pop('product')
product = Product.objects.create(**validated_data)
for product_data in products_data:
Product.objects.create(product=product, **product_data)
return product
Data receiving on GET method
{
"client_id": 3,
"currency": "0.05",
"billing_method": "credit card",
"first_name": "career",
"last_name": "lab",
"description": "NA",
"street_address": "tiliconveli",
"city": "tirunelveli",
"state": "tamilnadu",
"country": "India",
"pincode": "600200",
"industry": "software",
"company_size": 100,
"client_name": "techfetch",
"contact_no": "1234567890",
"mobile_no": "1234567890",
"email_id": "icanio#gamil.com",
"client_logo": "https://icanio-project-management.s3.amazonaws.com/client_logo/sup_bat_fDauRxK.jpg",
"client_code": "TFH",
"product": [
{
"product_id": 5,
"product_name": "time"
}
]
}
But while posting it in the same format it is not getting posted, showing like
{
"status": "error",
"code": 400,
"data": {
"product": [
"This field is required."
]
},
"message": "success"
}
Views.py for reference
class Client_Viewset(DestroyWithPayloadMixin,viewsets.ModelViewSet):
renderer_classes = (CustomRenderer, )
queryset=models.Client.objects.all()
serializer_class=serializers.Client_Serializers
parser_classes = [MultiPartParser, FormParser]
filter_fields = (
'client_id',
'client_name',
'client_code',
'org_id',
)
How can I post the same data which I get in the GET request of Product field. Please help me resolve this as I was stuck in there for two days. I tried so many ways and end up not getting posted.
Product model
class Product(models.Model):
product_id = models.AutoField(unique=True, primary_key=True)
product_name = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "product_master"
def __str__(self):
return self.product_name
product serializer
class Product_Serializers(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('product_id','product_name',)
From your code, the Client_Serializers is for Client model but the create method is not creating any Client object.
Client_Serializers should be something on these lines -
class Client_Serializers(serializers.ModelSerializer):
product = Product_Serializers(many=True)
class Meta:
model = Client
fields = ('client_id','currency','billing_method','first_name','last_name','description','street_address','city','state','country','pincode','industry','company_size','client_name', 'contact_no','mobile_no', 'email_id','client_logo','client_code','product',)
def create(self, validated_data):
products_data = validated_data.pop('product')
client = Client.objects.create(**validated_data) # Create a client object
for product_data in products_data:
Product.objects.create(client=client, **product_data)
return client
I'm creating a music rating app and I'm making a serializer for albums which has many relations and one aggregation method serializer which I think is causing all the trouble. The method gets average and count of reviews for every album. Is there any way I can decrease the number of queries for more performance?
All my models
class Artist(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
image = models.FileField(null=True, blank=True,
upload_to=rename_artist_image)
background_image = models.FileField(
null=True, blank=True, upload_to=rename_artist_bg_image)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return self.name
class Album(models.Model):
RELEASE_TYPE_ALBUM_CHOICES = [
("LP", "LP"),
("EP", "EP"),
("Single", "Single"),
("Live", "Live"),
]
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
release_date = models.DateField(null=True)
artist_id = models.ForeignKey(
Artist, on_delete=models.PROTECT, related_name="albums"
)
art_cover = models.FileField(
null=True, blank=True, upload_to=rename_album_art_cover)
release_type = models.CharField(max_length=10,
choices=RELEASE_TYPE_ALBUM_CHOICES, default="LP")
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return self.title
class Genre(models.Model):
name = models.CharField(max_length=255)
def __str__(self) -> str:
return self.name
class AlbumGenre(models.Model):
album_id = models.ForeignKey(
Album, on_delete=models.PROTECT, related_name="album_genres")
genre_id = models.ForeignKey(
Genre, on_delete=models.PROTECT, related_name="album_genres")
def __str__(self) -> str:
return self.genre_id.name
class AlbumLink(models.Model):
SERVICE_NAME_CHOICES = [
("spotify", "Spotify"),
("tidal", "Tidal"),
("amazonMusic", "Amazon Music"),
("appleMusic", "Apple Music"),
]
service_name = models.CharField(
max_length=15, choices=SERVICE_NAME_CHOICES)
url = models.CharField(max_length=255)
album_id = models.ForeignKey(
Album, on_delete=models.PROTECT, related_name="album_links")
def __str__(self) -> str:
return f"{self.service_name} - {self.url}"
class Track(models.Model):
title = models.CharField(max_length=255)
position = models.PositiveIntegerField()
album_id = models.ForeignKey(
Album, on_delete=models.PROTECT, related_name="tracks")
duration = models.DurationField(null=True)
def __str__(self) -> str:
return f"{self.position}. {self.title} - {self.duration}"
class AlbumOfTheYear(models.Model):
album_id = models.OneToOneField(
Album, on_delete=models.PROTECT, related_name="aoty")
position = models.IntegerField()
def __str__(self) -> str:
return str(self.position)
class Review(models.Model):
reviewer_id = models.ForeignKey(Reviewer, on_delete=models.PROTECT)
rating = models.IntegerField(
validators=[MaxValueValidator(100), MinValueValidator(0)]
)
review_text = models.TextField(null=True)
album_id = models.ForeignKey(
Album, on_delete=models.PROTECT, related_name="reviews")
created_at = models.DateTimeField(auto_now_add=True)
That's how album serializer looks.
"id": 2,
"title": "OK Computer",
"slug": "ok-computer",
"created_at": "2022-02-22T21:51:52.528148Z",
"artist": {
"id": 13,
"name": "Radiohead",
"slug": "radiohead",
"image": "http://127.0.0.1:8000/media/artist/images/radiohead.jpg",
"background_image": "http://127.0.0.1:8000/media/artist/bg_images/radiohead.jpg",
"created_at": "2022-02-22T00:00:00Z"
},
"art_cover": "http://127.0.0.1:8000/media/album/art_covers/ok-computer_cd5Vv6U.jpg",
"genres": [
"Alternative Rock",
"Art Rock"
],
"reviews": {
"overall_score": null,
"number_of_ratings": 0
},
"release_date": "1997-05-28",
"release_type": "LP",
"tracks": [
{
"position": 1,
"title": "Airbag",
"duration": "00:04:47"
},
{
"position": 2,
"title": "Paranoid Android",
"duration": "00:06:27"
}
],
"links": [
{
"service_name": "spotify",
"url": "https://open.spotify.com/album/6dVIqQ8qmQ5GBnJ9shOYGE?si=L_VNH3HeSMmGBqfiqKiGWA"
}
],
"aoty": null
Album serializer with method that gets average and count of reviews of album
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
genres = StringRelatedField(
source="album_genres", many=True, read_only=True)
aoty = StringRelatedField(read_only=True)
links = AlbumLinkSerializer(
source="album_links", many=True, read_only=True)
artist = SimpleArtistSerializer(source="artist_id")
def get_avg_and_count_of_reviews(self, album: Album):
reviews = Review.objects.only("rating").filter(album_id=album.id).aggregate(
overall_score=Avg(F("rating"), output_field=IntegerField()), number_of_ratings=Count(F("rating"), output_field=IntegerField()))
return reviews
reviews = serializers.SerializerMethodField(
method_name="get_avg_and_count_of_reviews")
class Meta:
model = Album
fields = ["id",
"title",
"slug",
"created_at",
"artist",
"art_cover",
"genres",
"reviews",
"release_date",
"release_type",
"tracks",
"links",
"aoty"]
# Save slug
def create(self, validated_data):
slug = slugify(validated_data["title"])
return Album.objects.create(slug=slug, **validated_data)
Here is a queryset in album Viewset
class AlbumViewSet(ModelViewSet):
queryset = Album.objects.prefetch_related("tracks").prefetch_related("album_genres").prefetch_related(
"album_links").prefetch_related("reviews").select_related("aoty").select_related("artist_id").all()
First you need to change your aggregate that you call once for every Album to an annotation, this will remove all of those extra aggregation queries
class AlbumViewSet(ModelViewSet):
queryset = Album.objects.prefetch_related(
"tracks",
"album_genres",
"album_links",
"reviews"
).select_related(
"aoty",
"artist_id"
).annotate(
overall_score=Avg(F("reviews__rating"), output_field=IntegerField()),
number_of_ratings=Count(F("reviews__rating"), output_field=IntegerField())
)
Now you can replace your reviews field with two regular IntegerFields
class AlbumSerializer(serializers.ModelSerializer):
...
overall_score = serializers.IntegerField(source="overall_score")
number_of_ratings = serializers.IntegerField(source="number_of_ratings")
Here is my code:
# VIEW.PY
def retrieve(self, request, pk=None):
variant_id = request.get('variant_id')
queryset = Category.objects.filter(category_id=pk)
querysetSerializer = CategoryServiceListSerializer(queryset, many=True)
i want to filter variant_id from Variant so that it display only that particular variuant. Not sure where changes need to be made in views or serialzier.
im assuming this could be solution
queryset = Category.objects.filter(category_id=pk,variant__in = variant_id)
but getting error TypeError: 'int' object is not iterable
# MODELS.PY
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
category_name = models.CharField(max_length=50)
category_icon = models.CharField(max_length=500, null=True, blank=True)
category_image = models.CharField(max_length=500, null=True, blank=True)
category_description = models.CharField(max_length=1000, null=True, blank=True)
active_status = models.BooleanField(default=True)
class Variant(models.Model):
variant_id = models.AutoField(primary_key=True)
service_id = models.ManyToManyField(Services)
category_id = models.ManyToManyField(Category)
variant_name = models.CharField(max_length=100)
variant_icon = models.CharField(max_length=1000, null=True, blank=True)
variant_image = models.CharField(max_length=1000, null=True, blank=True)
variant_description = models.CharField(max_length=5000, null=True, blank=True)
active_status = models.BooleanField(default=True)
# SERIALIZER.PY
class CategoryServiceListSerializer(serializers.ModelSerializer):
variant = VariantServiceSerializer(many=True, source="variant_set")
class Meta:
fields = "__all__"
model = Category
class VariantServiceSerializer(serializers.ModelSerializer):
class Meta:
model = Variant
fields = "__all__"
output:
"data": {
"category_id": 1,
"category_name": "Home Cleaning",
"variant": [
{
"variant_id": 1,
"variant_name":
},
{
"variant_id": 2,
"variant_name":
},
{
"variant_id": 3,
"variant_name":
},
{
"variant_id": 2,
"variant_name":
}
]
}
Expected_output:
req:
{"variant_id:1}
responce:
{
"category_id": 1,
"category_name": "Home Cleaning",
"variant": {
"variant_id": 1,
"variant_name":
}
One thing you can do is to make variant a SerializerMethodField then filter against parameters passed in the context.
In your view:
def retrieve(self, request, pk=None):
variant_id = request.get('variant_id')
queryset = Category.objects.filter(category_id=pk)
querysetSerializer = CategoryServiceListSerializer(queryset, many=True, context={'variant_id': variant_id})
[...]
In your serializer:
class CategoryServiceListSerializer(serializers.ModelSerializer):
variant = SerializerMethodField()
def get_variant(self, instance):
variant_id = self.context.get('variant_id')
if variant_id:
variants = instance.variant_set.filter(variant_id=variant_id)
else:
variants = instance.variant_set.all()
return VariantServiceSerializer(variants, many=True).data
class Meta:
fields = "__all__"
model = Category
I'm using Django and Django Rest Framework to represent a 'BaseRecipe' model. This model has a M2M field to represent the ingredients of that recipe. That M2M field relates a 'Product' object with the 'BaseRecipe' object and extends that two models with another field to represent the 'quantity'. I'm trying to retrieve a list of those ingredients in the BaseRecipeSerializer, but only the id's are returned.
Any ideas why?
Thank you in advance!
My models.py:
class Product(models.Model):
name = models.CharField(_('Name'), max_length=255, help_text=_('Product name'))
supplier = models.ForeignKey(Supplier, blank=True, related_name='supplier_products', on_delete=models.CASCADE)
serial_no = models.CharField(_('Serial number'), max_length=50, blank=True,
help_text=_('Product serial number. Max 50 characters.'))
allergens = models.ManyToManyField(Allergen, blank=True, related_name='product_allergens')
description = models.TextField(_('Description'), blank=True, help_text=_('Additional product information.'))
is_vegan = models.BooleanField(_('Vegan'), default=False)
is_halal = models.BooleanField(_('Halal'), default=False)
format_container = models.CharField(_('Format container'), max_length=6, choices=CONTAINERS, blank=True,
help_text=_('Package format'))
format_quantity = models.DecimalField(_('Format quantity'), blank=True, null=True, max_digits=9, decimal_places=3,
help_text=_('Format quantity sell'))
format_unit = models.CharField(_('Format unit'), max_length=6, choices=UNITS, blank=True)
quantity = models.DecimalField(_('Quantity'), blank=True, null=True, max_digits=9, decimal_places=3,
help_text=_('Quantity per unit provided'))
type = models.CharField(_('Type'), max_length=255, help_text=_('Type'), blank=True)
unit = models.CharField(_('Unit'), max_length=6, choices=UNITS)
unit_price = models.DecimalField(_('Unit price'), blank=True, null=True, max_digits=9, decimal_places=3)
class Meta:
ordering = ['name', ]
#property
def price(self) -> Decimal:
return self.quantity * self.unit_price
def __str__(self):
return self.name
class BaseRecipe(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name='user_base_recipes')
restaurant = models.ForeignKey(Restaurant, null=True, on_delete=models.SET_NULL,
related_name='restaurant_base_recipes')
title = models.CharField(_('Base recipe title'), max_length=255, help_text=_('Base recipe. Example: Chicken broth'),
blank=True)
elaboration = models.TextField(_('Elaboration'), blank=True, help_text=_('Base recipe making instructions.'))
quantity = models.DecimalField(_('Quantity'), max_digits=9, decimal_places=3,
help_text=_('Quantity produced with this recipe (after cooking). '))
unit = models.CharField(_('Unit'), max_length=6, choices=UNITS)
expiry_date = models.DateField(_('Expiry date'), help_text=_('Last day product is safe to consume.'))
ingredients = models.ManyToManyField(Product, through='IngredientBaseRecipe', related_name='base_recipe_ingredients')
image = models.ImageField(_('Picture'), upload_to=get_picture_path, blank=True, null=True)
exhausted = models.BooleanField(_('Exhausted'), default=False, help_text=_('If it\'s needed to produce more.'))
next_batch_date = models.DateField(_('Next batch date'), blank=True,
help_text=_('When it\'s necessary to prepare more of this base recipe.'))
storage = models.CharField(_('Storage'), max_length=12, choices=STORAGE_METHODS, blank=True)
class Meta:
ordering = ['-id']
#property
def cost(self) -> Decimal:
return sum([ingredient.cost for ingredient in self.ingredients.all()])
#property
def allergens(self):
allergens_ids = IngredientBaseRecipe.objects.filter(base_recipe=self).values_list('product__allergens',
flat=True)
allergens = Allergen.objects.filter(id__in=allergens_ids)
return allergens
def __str__(self):
return self.title
class IngredientBaseRecipe(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
base_recipe = models.ForeignKey(BaseRecipe, on_delete=models.CASCADE)
product_quantity = models.DecimalField(_('Product quantity'), max_digits=9, decimal_places=3, default=0.0)
class Meta:
ordering = ['-id']
#property
def allergens(self):
return self.product.allergens.all()
#property
def cost(self) -> Decimal:
return self.quantity * self.product.unit_price
def __str__(self):
return self.product.name
serializer.py:
class SimpleProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['id', 'name', ]
class IngredientBaseRecipeSerializer(serializers.ModelSerializer):
# product_name = serializers.ReadOnlyField(source='product.name')
product = SimpleProductSerializer(read_only=True)
class Meta:
model = IngredientBaseRecipe
exclude = ['base_recipe', ]
class BaseRecipeSerializer(serializers.ModelSerializer):
ingredients = IngredientBaseRecipeSerializer(many=True, read_only=True)
allergens = AllergenSerializer(many=True, read_only=True)
cost = serializers.FloatField(read_only=True)
class Meta:
model = BaseRecipe
fields = '__all__'
Result:
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 5,
"ingredients": [
{
"id": 1
},
{
"id": 3
},
{
"id": 3
}
],
"allergens": [
{
"id": 9,
"name": "Celery",
"icon": null
},
{
"id": 12,
"name": "Sulphites",
"icon": null
}
],
"title": "Tipical Spanish",
"elaboration": "No se tio.",
"quantity": "23232.000",
"unit": "l",
"expiry_date": "2021-02-28",
"image": null,
"exhausted": false,
"next_batch_date": "2021-03-01",
"storage": "freezer",
"user": 1,
"restaurant": 1
},
{
"id": 3,
"ingredients": [],
"allergens": [],
"cost": 0.0,
"title": "Chicken broth",
"elaboration": "One, two, three.",
"quantity": "45.000",
"unit": "l",
"expiry_date": "2021-02-28",
"image": null,
"exhausted": false,
"next_batch_date": "2021-03-01",
"storage": "freezer",
"user": 1,
"restaurant": 1
}
]
}
BaseRecipe.ingredients will return a queryset of Product instances but you are passing them to the IngredientBaseRecipeSerializer. You need to change the source for this field so that you pass the related IngredientBaseRecipe instances to this field
class BaseRecipeSerializer(serializers.ModelSerializer):
ingredients = IngredientBaseRecipeSerializer(
many=True,
read_only=True,
source='ingredientbaserecipe_set'
)
...
I have following setup
Models
class Day(models.Model):
date = models.DateField(auto_now=False, auto_now_add=False)
price = models.FloatField()
paymentMethod = models.CharField(max_length = 200)
class Reservation(models.Model):
start = models.DateField(verbose_name='Заезд', auto_now=False, auto_now_add=False)
end = models.DateField(verbose_name='Выезд', auto_now=False, auto_now_add=False)
hasRefund = models.BooleanField(verbose_name='Возвратная бронь', default=True)
room = models.ForeignKey('Room', verbose_name='Номер', on_delete=models.CASCADE)
day = models.ManyToManyField(Day, blank=True)
check_in_time = models.CharField(verbose_name='Время заезда', max_length=200)
check_out_time = models.CharField(verbose_name='Время выезда', max_length=200)
guest_name = models.CharField(verbose_name='Имя гостя', max_length=200, blank=True)
payed = models.BooleanField(verbose_name='Оплачено', default=False)
class Room(models.Model):
name = models.CharField(max_length = 200, null=True)
Views
class ReservationCreateAPIView(CreateAPIView):
queryset = Reservation.objects.all()
serializer_class = ReservationSerializer
Serializers
class DaySerializer(serializers.ModelSerializer):
class Meta:
model = Day
fields = [
'date',
'price',
'paymentMethod',
]
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = [
'pk',
'name',
]
class ReservationSerializer(serializers.ModelSerializer):
room = RoomSerializer
day = DaySerializer(many=True)
class Meta:
model = Reservation
fields = [
'start',
'end',
'hasRefund',
'room',
'day',
'check_in_time',
'check_out_time',
'guest_name',
'payed',
]
def create(self, validated_data):
day_data = validated_data.pop('day')
room_data = validated_data.pop('room')
reservation = Reservation.objects.create(**validated_data)
room = Room.objects.get_or_create(name=room_data['name'])
reservation.room.add(room)
for day in day_data:
day, created = Day.objects.get_or_create(date=day['date'], price=day['price'], paymentMethod=day['paymentMethod'])
reservation.day.add(day)
return reservatrion
Data, that I try to save
{
"start": "2017-12-12",
"end": "2017-12-12",
"hasRefund": false,
"room": 2,
"day": [ {
"date": "2017-12-12",
"price": "2",
"paymentMethod": "3"
},
{
"date": "2017-12-12",
"price": "2",
"paymentMethod": "3"
}
],
"check_in_time": "14-00",
"check_out_time": "12-00",
"guest_name": "Ivan",
"payed": false
}
Response that I get
IntegrityError at /core/create/
NOT NULL constraint failed: core_reservation.room_id
What Am I doing wrong ?
You try to create a Reservation without its Room. Your reservation model doesn't allow a null value for its room.
One way is to create a room first, then assign it to the reservation:
room_data = validated_data.pop('room')
room = Room.objects.get_or_create(name=room_data['name'])
validated_data.update({'room': room})
reservation = Reservation.objects.create(**validated_data)
You can also simply allow reservations without a room and add the room afterwards. In your model use:
room = models.ForeignKey(
'Room',
null=True, blank=True,
verbose_name='Номер',
on_delete=models.CASCADE,
)
Then add the room to a reservation instance:
room_data = validated_data.pop('room')
reservation = Reservation.objects.create(**validated_data)
room = Room.objects.get_or_create(name=room_data['name'])
reservation.room = room
reservation.save()