I have 2 models - Rooms and Modules. A module can contain many rooms and a room can be contained by many different modules. below are the models -
Rooms model -
class Rooms(models.Model):
room_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
desc = models.TextField()
level = models.CharField(max_length=100)
Module model -
class Module(models.Model):
module_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
desc = models.TextField()
is_deleted = models.BooleanField(default=False)
rooms = models.ManyToManyField(Rooms)
Module serializer -
class ModuleSerializer(serializers.ModelSerializer):
rooms = RoomSerializer(read_only=True, many=True)
class Meta:
model = Module
fields = "__all__"
Module view.py file -
class add_module(APIView):
def post(self, request, format=None):
module_serializer = ModuleSerializer(data=request.data)
if module_serializer.is_valid():
module_serializer.save()
return Response(module_serializer.data['module_id'], status = status.HTTP_201_CREATED)
return Response("response":module_serializer.errors, status = status.HTTP_400_BAD_REQUEST)
How do I take multiple rooms as input in views.py file while creating my module object. Also if i want to test my API in postman, then how can i take multiple inputs in postman.
You can use a similar construction:
class ModuleSerializer(serializers.ModelSerializer):
rooms = RoomSerializer(read_only=True, many=True)
class Meta:
model = Module
fields = "__all__"
def create(self, validated_data):
rooms = validated_data.pop('rooms')
...
for room in rooms:
...
return Response(...)
Related
Let us imagine that I have two models.
First model contains curse details and user that created this course
class Course(models.Model):
course_name = models.CharField(max_length=100, null=False)
description = models.CharField(max_length=255)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
and my second model is:
class Lesson(models.Model):
course = models.OneToOneField(Course, on_delete=models.CASCADE) #
# inside the course I want my APIVIEW to list only the courses that current user created.
# OnetoOne relationship does not solve the problem.
status = models.CharField(choices=STATUS, null=False, default=GOZLEMEDE,max_length=20)
tariffs = models.FloatField(max_length=5,null=False,default=0.00)
continues_off = models.CharField(max_length=2)
user_profile = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
My serializers for both Models:
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lesson
fields = ('course', 'status', 'tariffs', 'continues_off', 'user_profile')
def create(self, validated_data):
lesson = models.Lesson.objects.create(
course = validated_data['course'],
status = validated_data['status'],
tariffs=validated_data['tariffs'],
continues_off=validated_data['continues_off'],
user_profile=validated_data['user_profile']
)
return lesson
class CourseSerializer(serializers.ModelSerializer):
"""Serializers Course content"""
class Meta:
model = models.Course
fields = '__all__'
def create(self,validated_data):
course = models.Course.objects.create(
course_name = validated_data['course_name'],
description=validated_data['description'],
user_profile=validated_data['user_profile']
)
return course
My Viewset:
class LessonViewset(viewsets.ModelViewSet):
model = models.Lesson
serializer_class = serializers.LessonSerializer
authentication_classes = (SessionAuthentication,)
permission_classes = (IsAuthenticated,BasePermission,)
def get_queryset(self):
user_current = self.request.user.id
return models.Lesson.objects.filter(user_profile=user_current)
How can I get the desired result. I want to get the courses for the current user and show them as a dropdown list in my API view. Just only the courses that user created should be in the dropdown list not all.
OnetoOne relationship gives all results of course table.
i think change your view code to :
def get_queryset(self,id):
return model.objects.filter(user_profile=id)
#You do not need to call it again when you put the Lesson on the model
\
I have 2 models - Module and Room. A module can have zero or multiple rooms and a room can be added into multiple modules. So, there is a simple many-to-many relationship between them.
When I use post request, raw-data works, but not form-data.
module/models.py -
class Module(models.Model):
module_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
desc = models.TextField()
room_list = models.CharField(max_length = 100, blank=True)
rooms = models.ManyToManyField(Rooms, blank=True)
rooms/models.py -
class Rooms(models.Model):
room_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
level = models.CharField(max_length=100)
desc = models.TextField()
module/serializers.py -
class ModuleSerializer(serializers.ModelSerializer):
rooms = RoomSerializer(many=True)
class Meta:
model = Module
fields = '__all__'
def create(self, validated_data):
rooms_data = validated_data.pop('rooms')
module = Module.objects.create(**validated_data)
for data in rooms_data:
room = Rooms.objects.get(**data)
module.rooms.add(room)
return module
def update(self, instance, validated_data):
# Updating rooms
rooms_data = validated_data.get('rooms')
instance.rooms.clear()
for room_data in rooms_data:
room = Rooms.objects.get(**room_data)
instance.rooms.add(room)
# Updating other fields
fields = [
'title',
'desc',
'thumbnail',
'is_deleted',
]
for field in fields:
setattr(instance, field, validated_data[field])
instance.save()
return instance
rooms/serialier.py -
class RoomSerialize(serializers.ModelSerializer):
room_id = serializers.IntegerField()
class Meta:
model = Rooms
fields = "__all__"
module/views.py -
class add_module(APIView):
def post(self, request, format=None):
# Adding the rooms to module from room_list
new_request = request.data.copy()
room_list=[]
if 'room_list' in new_request:
room_list_data = list(new_request['room_list'].split(" "))
for room in room_list_data:
room_object = Rooms.objects.get(room_id=room)
room_serializer = RoomSerializer(room_object)
room_list.append(room_serializer.data)
new_request.update({'rooms':room_list})
# creating the module
module_serializer = ModuleSerializer(data=new_request)
if module_serializer.is_valid():
module_serializer.save()
return Response(module_serializer.data['module_id'])
return Response(module_serializer.errors)
POST request body for updating a module in POSTMAN -
{
"module_id": 2,
"room_list": "1 2",
"title": "4",
"desc": "22",
}
Pls notice that while taking input of ManyToMany field - "rooms", I'm taking a string "room_list" as input that contains all the room_ids to be included. This works perfectly fine when I take input as raw-data in postman, but when I use form-data, it shows
{
"rooms": [
"This field is required."
]
}
What to do?
First of all, serializer fields with (many=True) create nested objects.
If you input data with Rooms as already serialized, then it means that you create other Rooms instances. It will be shown with if module_serializer.is_valid(): part. Therefore, if you intended to implement as just link already instantiated Rooms to Module, it's better to make it as primary key list.
Here are my example codes.
class ModuleSerializer(serializers.ModelSerializer):
rooms = RoomSerializer(many=True, read_only=True)
def create(self, validated_data):
rooms_data = validated_data['room_list']
module = Module.objects.create(**validated_data)
for data in rooms_data.split(' '):
room = Rooms.objects.get(room_id=data)
module.rooms.add(room)
return module
def update(self, instance, validated_data):
# Updating rooms
rooms_data = validated_data.get('rooms')
instance.rooms.clear()
for room_data in rooms_data:
room = Rooms.objects.get(**room_data)
instance.rooms.add(room)
# Updating other fields
fields = [
'title',
'desc',
'thumbnail',
'is_deleted',
]
for field in fields:
setattr(instance, field, validated_data[field])
instance.save()
return instance
class Meta:
model = Module
fields = '__all__'
class AddModule(APIView):
def post(self, request, format=None):
# creating the module
module_serializer = ModuleSerializer(data=request.data)
if module_serializer.is_valid():
module_serializer.save()
return Response(module_serializer.data['module_id'])
return Response(module_serializer.errors)
Any other parts are same as yours. Regardless of whether data are sent by form-data or json raw data, results are same as below.
I have 2 models - Module and Room. A module can have zero or multiple rooms and a room can be added into multiple modules. So, there is a simple many-to-many relationship between them.
In post request, raw-data input works, but not form-data.
module/models.py -
class Module(models.Model):
module_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
desc = models.TextField()
rooms = models.ManyToManyField(Rooms, blank=True)
room_list = models.CharField(max_length = 100, blank=True)
rooms/models.py -
class Rooms(models.Model):
room_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
desc = models.TextField()
level = models.CharField(max_length=100)
module/serializers.py -
class ModuleSerializer(serializers.ModelSerializer):
rooms = RoomSerializerWrite(many=True)
class Meta:
model = Module
fields = '__all__'
def create(self, validated_data):
rooms_data = validated_data.pop('rooms')
module = Module.objects.create(**validated_data)
for data in rooms_data:
room = Rooms.objects.get(**data)
module.rooms.add(room)
return module
def update(self, instance, validated_data):
# Updating rooms
rooms_data = validated_data.get('rooms')
instance.rooms.clear()
for room_data in rooms_data:
room = Rooms.objects.get(**room_data)
instance.rooms.add(room)
# Updating other fields
fields = [
'title',
'desc',
'thumbnail',
'is_deleted',
]
for field in fields:
setattr(instance, field, validated_data[field])
instance.save()
return instance
rooms/serialier.py -
class RoomSerialize(serializers.ModelSerializer):
room_id = serializers.IntegerField()
class Meta:
model = Rooms
fields = "__all__"
module/views.py -
class add_module(APIView):
def post(self, request, format=None):
# Adding the rooms to module from room_list
new_request = request.data.copy()
room_list=[]
if 'room_list' in new_request:
room_list_data = list(new_request['room_list'].split(" "))
for room in room_list_data:
room_object = Rooms.objects.get(room_id=room)
room_serializer = RoomSerializer(room_object)
room_list.append(room_serializer.data)
new_request.update({'rooms':room_list})
# creating the module
module_serializer = ModuleSerializer(data=new_request)
if module_serializer.is_valid():
module_serializer.save()
return Response(module_serializer.data['module_id'])
return Response(module_serializer.errors)
POST request body for updating a module in POSTMAN -
{
"module_id": 2,
"room_list": "1 2",
"title": "4",
"desc": "22",
}
Pls notice that while taking input of ManyToMany field - "rooms", I'm taking a string "room_list" as input that contains all the room_ids to be included.
This works perfectly fine when I take input as raw-data in postman, but when I use form-data, it shows -
{
"rooms": [
"This field is required."
]
}
What to do?
Nested serializers don't work with multipart/form-data.
Please refer to the following issues:
https://github.com/encode/django-rest-framework/issues/7650
https://github.com/encode/django-rest-framework/issues/7262
How can I set values on to a ManyToManyField which specifies an intermediary model?
In the models.py
class BookUser(models.Model):
email = models.EmailField()
class Book(models.Model):
author_id= models.CharField(max_length=255)
send_to = models.ManyToManyField(BookUser, through='BookUserRelationship')
book_id = models.AutoField(primary_key=True)
file_size = models.CharField(null=True)
class BookUserRelationship(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
user = models.ForeignKey(BookUser, on_delete=models.CASCADE)
shared_date = models.DateTimeField(auto_now_add=True,null=True,blank=True)
Tried to update in serializers.py
class BookSerializer(serializers.ModelSerializer):
send_to = BookUserSerializer(many=True, read_only=True)
class Meta():
model = Book
fields = ('book_id', 'author_id','file_size','send_to')
class BookUserSerializer(serializers.ModelSerializer):
model = BookUser
fields = ('email')
In the views.py for listing the books by passing the book_id as query params
class BookListView(generics.ListCreateAPIView):
serializer_class = serializers.BookSerializer
def get(self, request, *args, **kwargs):
user = self.request.user
book_id = self.request.query_params.get('book_id', None)
if book_id:
book = models.Book.objects.filter(book_id=book_id)
return Response(serializers.BookSerializer(book[0]).data)
You don't need to do anything at all. You have already set the relevant data in your for loop, by creating the BookUserRelationship instances. That is the many-to-many relationship; you should just remove the instance.send_to.set(emails) line.
This one is interesting to solve. I am building a module to register address for hospital, medical store and doctors. There is an abstracted model PrimaryAddress and a subclass called MedicalStorePrimaryAddress, and more subclasses will use the same abstracted model. I am using django rest framework to get the listings based on proximity (latitude, longitude and city). Now how could I filter it all using parent class, i.e PrimaryAddress model as I want to filter all the entities, i.e hospital, medical store and doctor nearby.
I have looked into django-polymorphic library but it doesnt help with geodjango and abstract class.
Any help suggestion is appreciated. Thanks
Here is the code sample:
# MODELS
class PrimaryAddress(gismodels.Model):
street = gismodels.CharField(max_length=255)
city = gismodels.CharField(max_length=60)
state = gismodels.CharField(max_length=100,
choices=settings.US_STATES,
default="CT")
landmark = gismodels.TextField()
latitude = gismodels.FloatField(null=True, blank=True)
longitude = gismodels.FloatField(null=True, blank=True)
location = gismodels.PointField(null=True, blank=True)
objects = gismodels.GeoManager()
def __unicode__(self):
return self.street
class Meta:
verbose_name = "Address"
verbose_name_plural = "Addresses"
abstract = True
def save(self, *args, **kwargs):
if self.latitude and self.longitude:
self.location = Point(self.longitude, self.latitude)
super(PrimaryAddress, self).save(*args, **kwargs)
class MedicalStoreAddress(PrimaryAddress):
medical_store = gismodels.OneToOneField(MedicalStore, related_name="medical_store_address",
on_delete=gismodels.CASCADE, null=True, blank=True)
# objects = gismodels.GeoManager()
def __unicode__(self):
return self.street
class Meta:
verbose_name = "Medical Store Address"
verbose_name_plural = "Medical Store Addresses"
def save(self, *args, **kwargs):
if self.latitude and self.longitude:
self.location = Point(self.longitude, self.latitude)
super(MedicalStoreAddress, self).save(*args, **kwargs)
# VIEW
class ProximityFilter(ListAPIView):
serializer_class = AddressSerializer
# authentication_classes = (authentication.TokenAuthentication, authentication.SessionAuthentication,)
# permission_classes = (permissions.IsAuthenticated,)
pagination_class = StandardResultsSetPagination
def get_queryset(self):
longitude = self.kwargs.get('longitude')
latitude = self.kwargs.get('latitude')
city = self.kwargs.get('city')
current_point = GEOSGeometry('POINT(%s %s)' % (longitude, latitude), srid=4326)
# raise
queryset = MedicalStoreAddress.objects.filter(city__iexact=city, location__distance_lte=(current_point, D(mi=700000000))).distance(
current_point).order_by('distance')
return queryset
# SERIALIZER
class AddressSerializer(HyperlinkedModelSerializer):
class Meta:
model = DoctorPrimaryAddress
fields = ('pk', 'street', 'latitude', 'longitude', 'city')
This paste expires on 2018-03-29 21:26:23. View raw. Remove now (Why am I seeing this?) Pasted through web.