35π
Init the serializer with many=True
In your implementation this is really easy to accomplish:
serialized = MovieTicketSerializer(data=request.data, many=True)
Data is no single object but an array of objects.
Your infos suggest that you need to transform request.data to make those multiple objects (all the same data just different seat number). Right?
anyways:
see: How do I create multiple model instances with Django Rest Framework?
EDIT:
here the info in the drf docu: http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects
(highly suggest to read the drf docs from top to bottom and just playing around with it, before coding your first real implementation. there are many ways to use drf, and knowing all of them leads to better decisions)
EDIT 2 (after question update):
You could send this JSON from the client (see below), or create this format from the current JSON the client sends in your buy_ticket(request)
method before you call MovieTicketSerializer(...,many=True)
:
[
{
"purchased_at": null,
"qrcode": null,
"qrcode_data": "",
"show": 11,
"seat": 106,
"user": 34
},
{
"purchased_at": null,
"qrcode": null,
"qrcode_data": "",
"show": 11,
"seat": 219,
"user": 34
}
]
8π
This answer was a really good solution to this problem:
You can simply overwrite the get_serializer
method in your APIView and pass many=True
into get_serializer
of the base view like so:
class SomeAPIView(CreateAPIView):
queryset = SomeModel.objects.all()
serializer_class = SomeSerializer
def get_serializer(self, instance=None, data=None, many=False, partial=False):
if data is not None:
data.is_valid(raise_exception=True)
return super(SomeAPIView, self).get_serializer(instance=instance, data=data, many=True, partial=partial)
else:
return super(SomeAPIView, self).get_serializer(instance=instance, many=True, partial=partial)
As mentioned in the original post comments you then also have to call data.is_valid()
in cases where a data
keyword is passed to the serializer.
- [Django]-Get all table names in a Django app
- [Django]-"gettext()" vs "gettext_lazy()" in Django
- [Django]-Separation of business logic and data access in django
5π
You can check number of seats in the view function and create one or many tickets:
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def buy_ticket(request):
# Check if seats is a list
if isinstance(request.data['seat'], list):
seats = request.data.pop('seat')
models = []
for seat in seats:
# validate each model with one seat at a time
request.data['seat'] = seat
serializer = MovieTicketSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
models.append(serializer)
# Save it only after all seats are valid.
# To avoid situations when one seat has wrong id
# And you already save previous
saved_models = [model.save() for model in models]
result_serializer = MovieTicketSerializer(saved_models, many=True)
# Return list of tickets
return Response(result_serializer.data)
# Save ticket as usual
serializer = MovieTicketSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
It will work but honestly it is such a mess. You can move logic for seats creation in different function so it looks better.
- [Django]-Many-To-Many Fields View on Django Admin
- [Django]-Supervising virtualenv django app via supervisor
- [Django]-Django.core.exceptions.ImproperlyConfigured: Requested setting CACHES, but settings are not configured. You must either define the environment varia
1π
If you want the user to be able to select multiple seats for one ticket, its probably a good idea to remove the one-one mapping of Seat
and MovieTicket
, and create a many-one relationship. like so:
Serializers:
class SeatSerializer(serializers.ModelSerializer):
class Meta:
model = Seat
class MovieTicketSerializer(serializers.ModelSerializer):
seats = SeatSerializer(many=True)
class Meta:
model = MovieTicket
fields = '__all__'
def create(self, vlaidated_data):
seats = validated_data.pop('seats')
instance = MovieTicket.objects.create(
**validated_data)
for seat in seats:
Seat.objects.create(
movieticket=instance, **seats)
return instance
And the Model should look like:
class MovieTicket(models.Model):
show = models.ForeignKey(Show)
user = models.ForeignKey(User)
purchased_at = models.DateTimeField(default=timezone.now)
qrcode = models.ImageField(upload_to='qrcode', blank=True, null=True)
qrcode_data = models.CharField(max_length=255, unique=True, blank=True)
class Seat(models.Model):
movieticket = ForeignKey(
MovieTicket, related_name="movieticket")
# ... other fields.
This would then allow you to pass an array of βseatsβ in the request.
- [Django]-Django DoesNotExist
- [Django]-Django render_to_string missing information
- [Django]-How to use "AND" in a Django filter?
0π
If you donβt mind adding another app to your django project, you can try with django-rest-framework-bulk, if not you can check the code and see how it was implemented.
If you use this app, you will be able to perform bulk create operations, by sending a list of elements on your POST request.
e.g:
[{'name': 'Jane'}, {'name': 'John'}, {'name': 'Johny'}]
- [Django]-Get request data in Django form
- [Django]-Annotate a sum of two fields multiplied
- [Django]-How to write a query to get find value in a json field in django