multiple object creation on a single API call on django - django-rest-framework

i have to create multiple object creation on a single API call.My
serializer class is like this
def create(self, validated_data):
dt = datetime.now()
strg = '{:%d%m%Y%H%M%S}'.format(dt, dt.microsecond // 1000)
hat= "REQ" + strg
creater = dot_order_models.DotOrder(reqnum=hat,**validated_data)
creater.save()
return creater
class Meta:
model = dot_order_models.DotOrder
fields = ('merchant', 'biker','batch','customer_name','contact','city','locality','order_amount')
i just given many=true but did not work. then i give
def __init__(self, *args, **kwargs):
many = kwargs.pop('many', True)
super(BikerSerializer, self).__init__(many=many, *args, **kwargs)
this too didn't work.how can i solve it using serializers and view class.
thanks in advance

def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, many=isinstance(request.data, list))
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
results = dot_order_models.DotOrder.objects.all()
output_serializer = dot_order_serializers.DotOrderSerializer(results, many=True)
return super(DotOrderViewSet, self).create(request)

Related

Permission depends on field django rest framework

I'm trying to write little project which is using django rest framework and I have the Book model and rest api for that:
#models.py
class Book(models.Model):
name = models.CharField(max_length=100)
language = models.CharField(max_length=3, choices=LANGUAGES)
publication_date = models.CharField(max_length=4)
class Meta:
verbose_name = 'Книга'
verbose_name_plural = 'Книги'
def __str__(self):
return self.name
The next serialiser:
#serializers.py
class BookSerializer(serializers.Serializer):
name = serializers.CharField(max_length=120)
language = serializers.CharField()
publication_date = serializers.CharField()
def create(self, validated_data):
return Book.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.language = validated_data.get('language', instance.language)
instance.publication_date = validated_data.get(
'publication_date',
instance.publication_date
)
instance.save()
return instance
And the next view:
#views.py
class BookView(APIView):
http_method_names = ['get', 'post', 'put', 'delete']
def get(self, request):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response({"books": serializer.data})
def post(self, request):
book = request.data.get('book')
# Create an article from the above data
serializer = BookSerializer(data=book)
if serializer.is_valid(raise_exception=True):
book_saved = serializer.save()
return Response({"success": "Book '{}' created successfully".format(book_saved.name)})
def put(self, request, pk, *args, **kwargs):
saved_book = get_object_or_404(Book.objects.all(), pk=pk)
data = request.data.get('book')
serializer = BookSerializer(instance=saved_book, data=data, partial=True)
if serializer.is_valid(raise_exception=True):
book_saved = serializer.save()
return Response({
"success": "Book '{}' updated successfully".format(book_saved.name)
})
def delete(self, request, pk, *args, **kwargs):
book = get_object_or_404(Book.objects.all(), pk=pk)
book.delete()
return Response(
{"message": "Book with id `{}` has been deleted.".format(pk)},
status=204
)
How I can to implement permission which depends on publication_date field, literally if publication_date more than current date, then get request is available only for admins.
Instead of using Book.objects.all() everywhere, define a function:
def get_queryset(self, request):
if request.user.is_superuser:
return Book.objects.all()
else:
return Book.objects.filter(publication_date__lte=datetime.datetime.now())
Then call it like self.get_queryset(request).
This will only make books published earlier than right now to be visible to non-admins.
Also, you have a lot of boilerplate code. You should probably be using ModelViewSet

DRF request.data issue with POST method

I'm using DRF to test a api,when i POST a data,DRF return status_code 500 and error 'MacList' object has no attribute 'data'. but the GET is not problem.
Views:
class MacList(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
queryset = Testable.objects.all()
serializer_class = TestableSerializer
def get(self,request,*args,**kwargs):
return self.list(self, request, *args, **kwargs)
def post(self,request,*args,**kwargs):
return self.create(self, request, *args, **kwargs)
URLs:
path(r'api/maclist',views.MacList.as_view())
I'm checking the mixins.CreateModelMixin source code
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) **#### problem here**
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
if i use APIView to POST success.
class MacList(APIView):
def post(self,request):
serializer = TestableSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
Please help me!
Django-->3.0.8
djangorestframework-->3.11.0
Don't need to pass derived class instance into inherited class method while calling it from derived class, when we use self python automatically pass this instance
It will works if you change your code to
.
.
def get(self,request,*args,**kwargs):
return self.list(request, *args, **kwargs)
def post(self,request,*args,**kwargs):
return self.create(request, *args, **kwargs)

DRF - How to get created object in CreateAPIView

My goal very much resembles to what has been asked in this question but from the perspective of DRF, rather than forms.
So basically the question is, how can I get the newly created object in the following code snippet:
TestSerializer(serializers.ModelSerializer)
class Meta:
fields = '__all__'
model = TestModel
class TestView(generics.CreateAPIView):
serializer_class = TestSerializer
def create(self, request, *args, **kwargs):
response = super(TestView, self).create(request, *args, **kwargs)
created_model_instance = .... ?
print(created_model_instance.id)
return response
You can override perform_create and use serializer.save to get the created object, like:
class TestView(generics.CreateAPIView):
serializer_class = TestSerializer
def perform_create(self, serializer):
"""Some doc here!"""
obj = serializer.save()
print(obj.id)

DRF-Haystack SearchIndex returning from ALL index classes?

I'm using haystack with elasticsearch backend in django, and drf-haystack to implement serializers for results.
I first created a StudentIndex, which indexes over StudentProfiles to use in searches for students in search_indexes.py
class StudentIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(
document=True,
use_template=True,
template_name="search/indexes/user_search_text.txt")
//other indexes or indices or whatever
def get_model(self):
return StudentProfile
def index_queryset(self, using=None):
return StudentProfile.objects.filter(user__is_active=True)
Which is passed to the serializer and viewset in views.py:
class StudentSerializer(HaystackSerializer):
class Meta:
index_classes = [StudentIndex]
class StudentSearchView(ListModelMixin, HaystackGenericAPIView):
index_models = [StudentProfile]
serializer_class = StudentSerializer
pagination_class = None
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
and everything was fine and dandy....UNTIL I added two more indexes over other profiles and a single view/serializer to handle them. All exist in the same respective files:
search_indexes.py
class TeacherIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(
document=True,
use_template=True,
template_name="search/indexes/user_search_text.txt")
//other indexes or indices or whatever
def get_model(self):
return TeacherProfile
def index_queryset(self, using=None):
return TeacherProfile.objects.filter(user__is_active=True)
class StaffIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(
document=True,
use_template=True,
template_name="search/indexes/user_search_text.txt")
//other indexes or indices or whatever
def get_model(self):
return StaffProfile
def index_queryset(self, using=None):
return StaffProfile.objects.filter(user__is_active=True)
and added to views.py:
class StaffSerializer(HaystackSerializer):
class Meta:
index_classes = [StaffIndex, TeacherIndex]
class StaffSearchView(ListModelMixin, HaystackGenericAPIView):
index_models = [StaffProfile, TeacherProfile]
serializer_class = StaffSerializer
pagination_class = None
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
NOW....each view goes to its own url endpoint (/student-search and /staff-search respectively), but ONLY the staff-search endpoint properly returns Staff and TeacherProfile results, while the student-search, in a seperate endpoint with seperate view and models and indexes all explicitly stated, is return StudentProfiles AND Teacher and StaffProfiles and I can not for the life of me figure out why.
If anyone has run into this before, I'd really appreciate help solving, and more importantly, understanding, this issue.
Thanks in advance!
Well, for future people with the same issues, here's all i needed to do to solve it.
I'm using the DRF-Haystack genericviewapi, and on the view, I simply defined the filter_queryset to use the proper haystack connection (which ignored other indices). So for example:
class StudentSearchView(ListModelMixin, HaystackGenericAPIView):
index_models = [StudentProfile]
serializer_class = StudentSerializer
pagination_class = None
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def filter_queryset(self, queryset):
queryset = super(HaystackGenericAPIView, self).filter_queryset(queryset)
return queryset.using('student')
Everything now works properly :)
I have the same problem, but when i use the queryset.using('dynamic'), it raises django.core.exceptions.ImproperlyConfigured: The key 'dynamic' isn't an available connection.
class DynamicSearchView(ListModelMixin, HaystackGenericAPIView):
serializer_class = serializers.DynamicSearchSerializer
filter_backends = [HaystackHighlightFilter]
#swagger_auto_schema(
manual_parameters=[text, type]
)
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def filter_queryset(self, queryset):
return super(DynamicSearchView, self).filter_queryset(queryset).using('dynamic')

Where to add default value in CreateAPIView?

I have a ListCreateAPIView, on which I want to populate a field with a default value in case of not provided by request.DATA.
Problem is: where should I do that ?
I can't modify the request.DATA because it is immutable and I don't want to copy/paste the CreateMixin implementation.
Here is my code:
class ObjectiveList(generics.ListCreateAPIView):
model = Objective
serializer_class = ObjectiveSerializer
permission_classes = (permissions.IsAuthenticated,)
def create(self, request, *args, **kwargs):
# provide a default value
objective_definition_id = request.DATA.get('objective_definition',-1)
data = request.DATA.copy()
if objective_definition_id == -1:
# support for 0.9.1 version of iOS and below
logger.info(str(self.request.DATA))
mission_url = request.DATA["mission"]
objectivedefinition_pk = self.default_objectivedefinition_id(mission_url)
data["objective_definition"]=objectivedefinition_pk
# I would want to do something like this but I can't
# request.DATA = data
# super(ObjectiveList,self).create(request, *args, **kwargs)
# copy/paste of the super class implementation
serializer = self.get_serializer(data=data, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Here is my serializer:
class ObjectiveSerializer(serializers.HyperlinkedModelSerializer):
objective_definition = serializers.PrimaryKeyRelatedField(many=False, read_only=False, required=False, default=toto)
class Meta:
model = Objective
fields = (
'url',
'objective_definition',
)
You can use the default= argument on the field, don't know if that meets your use case?

Resources