access URL data in serializers class in Django Rest Framework - python-3.x

I'm getting None while accessing the data of the request.
views.py
def get(self, request, post_id, post_language_id, user_id):
...
paginator = CustomPageNumberPagination()
response = paginator.generate_response(language_liked_data, PostLanguageLikedSerializer, request)
return response
serializers.py
class PostLanguageLikedSerializer(serializers.ModelSerializer):
is_following = serializers.SerializerMethodField()
...
class Meta:
model = PostLanguageLike
fields = [...,'is_following']
def get_is_following(self, obj):
# here I'm getting None
user_id = self.context.get("user_id")
user_followings = UserFollowing.objects.filter(user_id=user_id, following_user_id=obj.user.id)
is_following = True if len(user_followings) > 0 else False
return is_following
but I need user_id from the URL so I found a way to access data through context. so I can access the value in the serializer.
views.py
def get(self, request, post_id, post_language_id, user_id):
...
language_liked_data = PostLanguageLike.objects.filter(post_language_id=post_in_lang.id)
post_language_like_serializer = PostLanguageLikedSerializer(language_liked_data, context={'user_id': user_id}, many=True)
return Response({"response": True, "return_code": "success", "result": {"liked_users": post_language_like_serializer.data}, "message": success["success"]}, status=200)
serializers.py
class PostLanguageLikedSerializer(serializers.ModelSerializer):
is_following = serializers.SerializerMethodField()
...
class Meta:
model = PostLanguageLike
fields = [...,'is_following']
def get_is_following(self, obj):
# here I want to access URL data.
user_id = self.context.get("user_id")
user_followings = UserFollowing.objects.filter(user_id=user_id, following_user_id=obj.user.id)
is_following = True if len(user_followings) > 0 else False
return is_following
the issue is I'm not able to use context={'user_id': user_id} with paginator.generate_response
is there any better way to get URL data in the serializer?

I got the answer on how to possibly get context data in the serializers.
views.py
paginator = CustomPageNumberPagination()
page = paginator.paginate_queryset(language_liked_data, request)
serializer = PostLanguageLikedSerializer(page, context={'user_id': user_id}, many=True)
response = paginator.get_paginated_response(serializer.data)
return response
paginator.py
def get_paginated_response(self, data):
# customize your response here "data" = "serializer.data"
return Response({
'links': {
'next': self.get_next_link(),
'previous': self.get_previous_link()
},
'count': self.page.paginator.count,
'results': data
})
serializers.py
class PostLanguageLikedSerializer(serializers.ModelSerializer):
is_following = serializers.SerializerMethodField()
...
class Meta:
model = PostLanguageLike
fields = [...,'is_following']
def get_is_following(self, obj):
# got context data here
user_id = self.context.get("user_id")
user_followings = UserFollowing.objects.filter(user_id=user_id, following_user_id=obj.user.id)
is_following = True if len(user_followings) > 0 else False
return is_following

Related

Django duplicate file to all the records with M2M which is self referencing

I have a Serializer & APIview where i upload a file it should be uploaded to other related records as well.
class Record(models.Model):
name = models.CharField(max_length = 122)
related_records = models.ManyToManyField('self', null = True)
class RecordDocument(models.Model):
record = models.ForeignKey(Record, related_name = 'documents', null = True,
blank= True )
file = models.FileField(max_length=255, blank=True, null=True)
class RecordDocumentSerializer(serializers.ModelSerializer):
save_documents_to_related_records = serializers.BooleanField()
class Meta:
model = RecordDocument
fields = ( 'save_documents_to_related_records', 'file',
'record' )
class RecordDocumentUploadView(APIView):
def post(self, request, *args, **kwargs):
'how do i get serializers field **save_documents_to_related_records** and save
the file on **related_records** which is not used in serializer till now if
there are any inside it'
You can try this.
class RecordDocumentUploadView(APIView):
def post(self, request, *args, **kwargs):
serializer = RecordDocumentSerializer(data = request.data)
if serializer.is_valid():
input_data = serializer.validated_data
flag = input_data.pop('save_documents_to_related_records')
new_document = RecordDocument.objects.create(**input_data)
if flag:
...
else:
return Response(status = status.HTTP_400_BAD_REQUEST)

How to capture a field instance during django-import-export upload

I'd like to import data into my resource minus the school field because the logged in user already belongs to a specific school. How would I do it without having the school field in my excel???
class uploadStudents(LoginRequiredMixin,View):
context = {}
def get(self,request):
form = UploadStudentsForm()
self.context['form'] = form
return render(request,'upload.html',self.context)
def post(self, request):
form = UploadStudentsForm(request.POST , request.FILES)
data_set = Dataset()
if form.is_valid():
file = request.FILES['file']
extension = file.name.split(".")[-1].lower()
resource = ImportStudentsResource()
if extension == 'csv':
data = data_set.load(file.read().decode('utf-8'), format=extension)
else:
data = data_set.load(file.read(), format=extension)
result = resource.import_data(data_set, dry_run=True, collect_failed_rows=True, raise_errors=True)
if result.has_validation_errors() or result.has_errors():
messages.success(request,f'Errors experienced during import.')
print("error", result.invalid_rows)
self.context['result'] = result
return redirect('import_students')
else:
result = resource.import_data(data_set, dry_run=False, raise_errors=False)
self.context['result'] = None
messages.success(request,f'Students uploaded successfully.')
else:
self.context['form'] = UploadStudentsForm()
return render(request, 'upload.html', self.context)
The resource
class ImportStudentsResource(resources.ModelResource):
school = fields.Field(attribute = 'school',column_name='school', widget=ForeignKeyWidget(School, 'name'))
klass = fields.Field(attribute = 'klass',column_name='class', widget=ForeignKeyWidget(Klass, 'name'))
stream = fields.Field(attribute = 'stream',column_name='stream', widget=ForeignKeyWidget(Stream, 'name'))
class Meta:
model = Student
fields = ('school','student_id','name','year','klass','stream')
import_id_fields = ('student_id',)
import_order = ('school','student_id','name','year','klass','stream')
Either remove 'school' from your 'fields' declaration, or add it to the 'exclude' list.
docs
Edit
To include a school_id which is associated with the logged in user, you'll need to create the Resource with this school_id:
Resource
class ImportStudentsResource(resources.ModelResource):
def __init__(self, school_id):
super().__init__()
self.school_id = school_id
def before_save_instance(self, instance, using_transactions, dry_run):
instance.school_id = self.school_id
post()
def post(self, request):
# skipped existing code
school_id = get_school_id_from_logged_in_user(self.request)
resource = ImportStudentsResource(school_id)

How to overwrite data from a model that is linked to the main model through a o-t-m relationship?

I have three models that are related to each other, namely:
models.py
class Shop(models.Model):
number = models.PositiveSmallIntegerField()
name = models.CharField(db_index=True)
city = models.ForeignKey(ShopCity, on_delete=models.CASCADE)
class Product(models.Model):
name = models.CharField(db_index=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
class ProductQuantity(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
shop = models.ForeignKey(Shop, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField(default=None)
In the admin panel they are linked in this way:
admin.py
class ProductQuantityInline(admin.TabularInline):
model = ProductQuantity
extra = 0
#admin.register(Product)
class ProductAdmin(ImportExportActionModelAdmin):
fields = ['name', 'price']
list_display = ['name', 'price']
inlines = [ProductQuantityInline]
There is a need to overwrite data with REST API
serializers.py
class QuantitySerializer(serializers.ModelSerializer):
class Meta:
model = ProductQuantity
fields = ('shop', 'quantity')
class ProductSerializer(serializers.ModelSerializer):
productquantity = serializers.SerializerMethodField(read_only=False)
class Meta:
model = Product
fields = ('name', 'price', 'productquantity')
def get_productquantity(self, obj):
return [QuantitySerializer(s).data for s in obj.productquantity_set.all()]
And finally my handler for REST API:
views.py
#api_view(['GET', 'PATCH', 'PUT', 'DELETE'])
def api_product_detail(request, pk):
product = Product.objects.get(pk=pk)
if request.method == 'GET':
serializer = ProductSerializer(product)
return Response(serializer.data)
elif request.method == 'PUT' or request.method == 'PATCH':
serializer = ProductSerializer(product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
product.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
As a result, data such as the name and price are overwritten, and the productquantity is not overwritten.
What am I doing wrong? Thanks for any help.

Image upload crud operations in django-restframework

Im new to django, i want to create API for image upload CRUD in drf.
i have done create and read images , it works but dont know how to update and delete it by using id
models.py
class File(models.Model):
file = models.FileField(blank=False, null=False)
def __str__(self):
return self.file.name
serializers.py
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
fields = "__all__"
views.py
class FileUploadView(ListAPIView):
parser_class = (FileUploadParser,)
serializer_class = FileSerializer
def get_queryset(self):
queryset = File.objects.all()
return queryset
def post(self, request, *args, **kwargs):
print(request.data)
file_serializer = FileSerializer(data=request.data)
print(file_serializer)
if file_serializer.is_valid():
file_serializer.save()
return Response(
file_serializer.data,
status=status.HTTP_201_CREATED
)
else:
return Response(
file_serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
i want to know how update and delete works
Thank you #manpikin, by doing this way, we can solve it easly
class FileViewSet(viewsets.ModelViewSet):
queryset = File.objects.all()
serializer_class = FileSerializer
but in my case there is some hidden code in between so i have done it in this way, i hope this will help some one facing same problem like me
views.py
class FileUploadView(ListAPIView):
parser_class = (FileUploadParser,)
serializer_class = FileSerializer
def get_queryset(self):
queryset = File.objects.all()
return queryset
def post(self, request, *args, **kwargs):
print(request.data)
file_serializer = FileSerializer(data=request.data)
print(file_serializer)
if file_serializer.is_valid():
file_serializer.save()
return Response(
file_serializer.data,
status=status.HTTP_201_CREATED
)
else:
return Response(
file_serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
def put(self, request):
imageid = self.request.POST.get('id')
f_obj = File.objects.filter(id=imageid) #File is my model name
file_serializer = FileSerializer(f_obj, data=request.data)
print(file_serializer)
if file_serializer.is_valid():
file_serializer.save()
return Response(
file_serializer.data,
status=status.HTTP_201_CREATED
)
else:
return Response(
file_serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
def delete(self, request):
imageid = self.request.POST.get('id')
f_obj = File.objects.filter(id=imageid) #File is my model name
if f_obj.exists():
f_obj.delete()
return Response(
{
"Status": True,
"Message": "image deleted"
}
)
update and delete will work in this way

filter ManyToManyField(**), by user in form selection

I need to add songs to my Playlist - but I want that only the user can add your registered songs, not all songs.
I have this:
models
class Song(models.Model):
user = models.ForeignKey(User, default=1)
title=models.CharField(max_length=500)
artist = models.CharField(max_length=250)
audio = models.FileField(default='')
def __str__(self):
return self.title
class List(models.Model):
user_list = models.ForeignKey(User, default=User)
title_list=models.CharField(max_length=500)
songs = models.ManyToManyField(Song)
def __str__(self):
return self.title_list
forms
class SongForm(forms.ModelForm):
class Meta:
model = Song
fields = ['title', 'artist', 'audio']
class ListForm(forms.ModelForm):
#songs=forms.MultipleChoiceField(Song.objects.all(), widget=forms.CheckboxSelectMultiple)
#songs= forms.MultipleChoiceField( widget=forms.CheckboxSelectMultiple)
#songs=forms.ModelMultipleChoiceField(queryset=Song.objects.all(), widget=forms.CheckboxSelectMultiple) #here i dont know why the form dont save data
#I want this
songs=forms.ModelMultipleChoiceField(queryset=Song.objects.filter(user=actualuser),widget=forms.CheckboxSelectMultiple)
class Meta:
model = Lista
fields = ['title_list','songs']
#views
def new_list(request):
form=ListForm(request.POST or None, request.FILES or None)
if form.is_valid():
lista = form.save(commit=False)
lista.user_list = request.user
lista.save()
context = {
'username': request.user.username,
'lista': lista,
}
return render(request,'MyMusic/list_detail.html',context)
context={
'form':form,
'error_message': 'Error ',
}
return render(request,'MyMusic/list_form.html',context)
in forms view I need only see and I want select only my own registered songs, also I want can see a check box not the actual (widget=forms.CheckboxSelectMultiple), but actully this does not save the data.
the solution for me.
**Forms**
class ListForm(forms.ModelForm):
def __init__(self,user, *args, **kwargs):
super(ListForm, self).__init__(*args, **kwargs)
self.fields['songs'] = forms.ModelMultipleChoiceField(queryset=Song.objects.filter(user=user)
,required=False,widget=forms.CheckboxSelectMultiple)
class Meta:
model = Lista
fields = ['title_list','songs']
in views
def new_list(request):
form=ListForm(request.user,request.POST or None, request.FILES or None)
if form.is_valid():
lista = form.save(commit=False)
lista.user_list = request.user
lista.save()
lista.canciones = form.cleaned_data['songs'] # avoid conflict to save checkbox
context = {
'username': request.user.username,
'lista': lista,
}
return render(request,'MyMusic/list_detail.html',context)
context={
'form':form,
'error_message': 'Error ',
}
return render(request,'MyMusic/list_form.html',context)

Resources