How to post multiple entries in REST - python

I am building REST API which stores name, salary and expenses of people. How can I POST data of multiple people at the same time, like an array?
This is my serializers.py file
from rest_framework import serializers
from .models import Bucketlist
class BucketlistSerializer(serializers.ModelSerializer):
class Meta:
model = Bucketlist
fields = ('id','name', 'date_created', 'salary','Expenditure')
read_only_fields = ('date_created',)
This is my views.py file

Django provides many=True attribute to pass while building queryset in your view. Please have a look on :
Multiple objects in serializer

you should use (many=True) in the serializer while saving
data = BucketlistSerializer(data = your_post_array,many=True)
if data.is_valid():
data.save()
add this to your view
def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
kwargs['many'] = True
return super("your view class name ", self).get_serializer(*args, **kwargs)
for function base view
#api_view(['GET','POST'])
def somefunction(request):
if request.method == 'POST':
data = BucketlistSerializer(data = request.data["key_for_data"], many=True)
if data.is_valid():
data.save()
return(data.data)
return(data.errors)
post data will be : {"key_for_data":[{},{}]

Related

Django Rest framework - data between two serializers do not validate

I have a API view in place where I first want to create a new user (already working) and second I want to return the new created user object using my UserSerializer (Not working).
views.py
#api_view(['POST'])
#permission_classes([AllowAny])
def user_create(request):
exception_handler = UserUnavailable
success_handler = UserCreated
if request.method == 'POST':
creation_serializer = CreateUserSerializer(data=request.data)
try:
if creation_serializer.is_valid(raise_exception=True):
creation_serializer.save()
user_serializer = UserSerializer(data=creation_serializer.instance.id)
if user_serializer.is_valid():
return JsonResponse({"status_code": success_handler.status_code,
"default_detail": success_handler.default_detail,
"default_code": success_handler.default_code,
"new_user": user_serializer,
}, safe=False)
except APIException:
return JsonResponse({"status_code": exception_handler.status_code,
"default_detail": exception_handler.default_detail,
"default_code": exception_handler.default_code
}, safe=False)
I can confirm that creation_serializer.instance.id contains the new users id.
serializers.py
class UserSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = get_user_model()
fields = ('id', 'user')
read_only_fields = ('id', 'user')
I can also confirm that
if user_serializer.is_valid()
does not validate for some reason. Any ideas
Thanks in advance
To initialize a serializer with user instance instead of
user_serializer = UserSerializer(data=creation_serializer.instance.id)
You should write something like this:
user_serializer = UserSerializer(instance=creation_serializer.instance)
instead of
Also, you don't have to validate the object that has already been saved.
And create a response you should like this:
return JsonResponse({
"status_code": success_handler.status_code,
"default_detail": success_handler.default_detail,
"default_code": success_handler.default_code,
"new_user": user_serializer.data,
}, safe=False)
But using api_view is now a bad thing. It's much better to use ModelViewSet. You can use something like this:
class UserViewSet(ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
def get_serializer_class(self, *args, **kwargs):
if self.action == 'create':
return CreateUserSerializer
return super().get_serializer_class(*args, **kwargs)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
response_serializer = self.serializer_class(instance=serializer.instance)
return Response(response_serializer.data, status=status.HTTP_201_CREATED, headers=headers)
And I'm sorry, I haven't tested it, there might be typos.
You can read about ModelViewsets more here https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset

how can insert multiple record using

I'm working on a small project Django Rest Framework, I already create add contact function as you can see in my create function. now I'm working on bulk import, but when I submit my data as a list not as a dict I get an error message :
{"non_field_errors":["Invalid data. Expected a dictionary, but got list."]}
this is my code to add a contact,
class ContactView(ListModelMixin, viewsets.GenericViewSet):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
def create(self, request):
serializeObject = ContactSerializer(data = request.data)
if serializeObject.is_valid():
serializeObject.save()
contactObject = Contact.objects.all()
contactSerializer = ContactSerializer(contactObject, many=True)
return Response(contactSerializer.data, status = status.HTTP_201_CREATED)
return Response(serializeObject.errors, status.HTTP_400_BAD_REQUEST)
Now i would like to create another function, for bulk create, since i have a list
This is my header data structure :
[{"Greeting":"amine","first_name":"alain","last_name":"amine","title":"ricardo","language":"ab#xyz.com","email":43822510594,"phone_1":43822510594,"phone_2":"not yet","mobile":43822510594,"fax":"not yet","internal_id":"xname"},{"Greeting":"bill","first_name":"microsoft","last_name":"bill","title":"microsoft","language":"bill#microsoft.com","email":652565455,"phone_1":652565455,"phone_2":"new york","mobile":652565455,"fax":"new york","internal_id":"microsoft"},{"Greeting":"john","first_name":"Yoyo","last_name":"Ruth","title":"xnameagain","language":"rh#xyz.com","email":5465559852,"phone_1":5465559852,"phone_2":"Vancouver","mobile":5465559852,"fax":"Vancouver","internal_id":"yname"}]
This is my serializer:
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = "__all__"
I found the Solution on https://www.django-rest-framework.org/api-guide/serializers/#dealing-with-multiple-objects
all what i have to do is to add many=True to create multiple object
serializeObject = ContactSerializer(data = request.data, many=True)
Create method should look like this:
class ContactView(ListModelMixin, viewsets.GenericViewSet):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
def create(self, request):
valid_objects = []
for data in request.data:
serializeObject = ContactSerializer(data=data)
if serializeObject.is_valid():
valid_objects.append(serializeObject)
else:
return Response(serializeObject.errors, status.HTTP_400_BAD_REQUEST)
for obj in valid_objects:
obj.save()
contactObject = Contact.objects.all()
contactSerializer = ContactSerializer(contactObject, many=True)
return Response(contactSerializer.data, status = status.HTTP_201_CREATED)
Advise
They may not be the best practices but it works.

Single CreateView in django for submitting multiple ModelForm data to multiple Model

I have a multiple modelforms form multiple model. I want one single CreateView for submitting all the values. I have three models(Employee, WorkExperience and Education). Models are connected using ForeignKey with each other.
forms.py:
class EmployeeAddModelForm(forms.ModelForm):
"""
Creates a form for employee invitations
"""
class Meta:
model = Employee
fields = [
'e_id',
'first_name',
'last_name',
'gender',
'religion',
]
class WorkExperienceForm(forms.ModelForm):
"""
Creates a form for saving employee work experiences
"""
class Meta:
model = WorkExperience
fields = [
'previous_company_name',
'job_designation',
'from_date',
'to_date',
'job_description',
]
class EducationForm(forms.ModelForm):
"""
Creates a form for saving educational info of an employee
"""
class Meta:
model = Education
fields = [
'institution_name',
'degree',
'passing_year',
'result',]
I have three model forms from three models in form.py. I want that my createview inherits all this modelforms and create a single form for posting data.
views.py:
class EmployeeAddView(LoginRequiredMixin,CreateView):
"""
Creates new employee
"""
login_url = '/authentication/login/'
template_name = 'employee/employee_add_form.html'
form_class = EmployeeAddModelForm
work_form_class = WorkExperienceForm
queryset = Employee.objects.all()
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
work_form = self.work_form_class(request.POST, prefix='work_form')
education_form = self.education_form_class(request.POST, prefix='education_form')
if form.is_valid() and work_form.is_valid():
instance = form.save()
work = work_form.save(commit=False)
education = education_form.save(commit=False)
work.employee = instance
education.employee = instance
work.save()
education.save()
if not education_form.is_valid():
print("Education")
return redirect('employee:employee-list')
def get_success_url(self):
return reverse('employee:employee-list')
I am rendering two forms from my view class. But when I use 'work_form' in my template.html, nothing appears.
How can I render all modelforms in my view?
override get function, because get request can not get work_form in default
def get(self, request, *args, **kwargs):
form = self.form_class(**self.get_form_kwargs())
work_form = self.work_form_class(prefix='work_form')
return render(request, self.template_name, {'form': form, 'work_form': work_form})

How to Query model filed elements in the same URL

I am writing a single model application in DRF. My model looks like this:
class Superhero(models.Model):
squad_name = models.CharField(max_length=100)
hometown = models.CharField(max_length=30)
formed = models.DateField()
active = models.BooleanField()
members = JSONField()
My viewset looks like this:
class SuperheroViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving superheros.
"""
serializer_class = SuperheroSerializer
def list(self, request):
"""list superhero object"""
queryset = Superhero.objects.filter()
serializer = SuperheroSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = Superhero.objects.filter()
superhero = get_object_or_404(queryset, pk=pk)
serializer = SuperheroSerializer(superhero)
return Response(serializer.data)
and finally, my router is:
router = DefaultRouter()
router.register(r'superhero', SuperheroViewSet, basename='superhero')
urlpatterns = router.urls
Now how do I set a URL,so I would query the members field like:
//superhero/{id}/members to get specific id members. I tried drf nested URL but didn't work. The url I have works for superhero/ and superhero/{id}.
You should use detailed viewset action.
Your code would looks smth like this:
from rest_framework.decorators import action
from rest_framework.shortcuts import get_object_or_404
from rest_framework.response import Response
class SuperheroViewSet():
...
#action(detail=True, methods=['get'], url_path='members')
def get_superhero_members(self, request, pk=None):
superhero = get_object_or_404(self.get_queryset(), pk=pk)
members = <get members of your hero>
return Response(members)
You should also probably use custom serializer for members and in response return: return Response(CustomSerializer(members).data)

Django json field to form fields

I have a django app that into the model has a json field looks like this
from json_field import JSONField
from django.db import models
class C(models.Model):
name = models.CharField(max_length=255)
jf = JSONField(null=False)
There is a form that display this as follow
class Edit(forms.Form):
name = forms.CharField()
def __init__(self, *args, **kwargs):
if 'extra' in kwargs:
extra = kwargs.pop('extra')
super(Edit, self).__init__(*args, **kwargs)
for k, v in extra.iteritems():
self.fields['%s' % k] = v
else:
super(Edit, self).__init__(*args, **kwargs)
The view will load the json field jf and send it to the Form as initial data, as well
will send all the necessary fields as extra.
def edit_model(request, pk):
obj = get_object_or_404(models.C, pk=pk)
initial = model_to_dict(obj)
form = Edit(request.POST or None, initial=initial, extra=initial['jf'])
if request.method == 'POST':
if form.is_valid():
.....
# what is the best practice here ?
# intersect cleaned data with the jf fields ?!
# have an external entity that does this ?!
# is anything built into django that can help
thanks!
If I understood you can try this custom widget's form of django It does JSON to formfields and formfields -> JSON after save

Categories