How to set the DestroyAPIView method not real delete my instance? - python

I have a model, like bellow:
class BModel(models.Model):
name = models.CharField(max_length=11)
status = models.CharField(default="is_active") # if delete: deleted
a = models.ForeignKey(AModel)
def delete(self, using=None, keep_parents=False):
pass # there I want to set the BModel's status to `deleted`
Serializer:
class BModelSerializer(ModelSerializer):
class Meta:
model = BModel
fields = "__all__"
Its Views is bellow:
class BModelListAPIView(ListAPIView):
serializer_class = BModelSerializer
permission_classes = []
queryset = BModel.objects.all()
class BModelDestroyAPIView(DestroyAPIView):
serializer_class = BModelSerializer
permission_classes = []
queryset = BModel.objects.all()
My requirement is when use Django-Rest-Framework delete my BModel, I want to set the BModel's status field to deleted, not real delete the instance. How to access it?
when I tried to write a delete method to my Model, there comes the default delete method:
def delete(self, using=None, keep_parents=False):
I have some questions about this:
Is this is for the BModel's instance?
Whether should through the delete method to access my requirement?

DestroyAPIView has a perform_destroy method. You can override that and add your logic of deletion. For eg:
class BModelDestroyAPIView(DestroyAPIView):
serializer_class = BModelSerializer
permission_classes = []
queryset = BModel.objects.all()
def perform_destroy(self, instance):
instance.delete_flag = True
instance.save()
The delete method of BModel will override the default delete method. Which will also affect the Django Admin. You can also add a custom delete method to Manager of that Model. Refer

Related

How to inherit Generic Filtering in extra action

I want to inherit Generic Filtering include (filterset_fields, search_fields, ordering_fields in extra action sold. So how to do it, and any way better for this case?
class ApartmentViewset(viewsets.ModelViewSet):
queryset = Apartment.objects.all().order_by('-timestamp')
serializer_class = ApartmentSerializer
# Set permission for only user owner apartment can edit it.
permission_classes = [
permissions.IsAuthenticatedOrReadOnly, IsOwnerApartmentOrReadOnly]
# Add search by address, filter by district and ordering by price
filter_backends = [filters.SearchFilter,
DjangoFilterBackend, filters.OrderingFilter]
filterset_fields = ['district']
search_fields = ['address', 'seller']
ordering_fields = (
'price',
)
# fill current username when create new apartment
def perform_create(self, serializer):
serializer.save(seller=self.request.user)
#action(detail=False)
def sold(self, request):
queryset = self.queryset.filter(issold=True)
serialize = self.serializer_class(queryset, many=True)
return Response(serialize.data)
Generic View (and hence all classes that inherit from it) in DRF has a filter_queryset method which is called by the various mixins to perform filtering, so you can simply call that in your method. If you also want pagination there are the methods paginate_queryset and get_paginated_response:
class ApartmentViewset(viewsets.ModelViewSet):
...
#action(detail=False)
def sold(self, request):
queryset = self.filter_queryset(self.queryset.filter(issold=True))
serialize = self.serializer_class(queryset, many=True)
return Response(serialize.data)

How to serialize ManyToManyField

I want to serialize ManyToManyField but at the same time, I am looking for something which updates the same using ModelViewSet. I am able to serialize it but when I am updating it I am not able to. I know I can make a separate API for that but due to some requirements, I need to stick to one endpoint. Here is my code
class ComponentSerializers(serializers.ModelSerializer):
class Meta:
model = coreModel.Component
fields = '__all__'
class MonitorSerializers(serializers.ModelSerializer):
device = ComponentSerializers(read_only=True, many=True)
class Meta:
model = models.Monitor
fields = '__all__'
read_only_fields = ('id', 'created_at', 'updated_at',)
and views.py is
class MonitorViewSet(viewsets.ModelViewSet):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
queryset = models.Monitor.objects.all()
filter_backends = (DjangoFilterBackend,OrderingFilter,SearchFilter)
filter_class = superFilter.MonitorFilters
serializer_class = serializers.MonitorSerializers
If you want update ManytoMany or Related objects
Override
def update(self, validated_data):
in MonitorSerializers
class MonitorSerializers(serializers.ModelSerializer):
device = ComponentSerializers(read_only=True, many=True)
device_ids = serializers.ListField(write_only=True,
child = serializers.IntegerField(min_value = 1))
....
def update(self, instance, validated_data):
# Remove component data and save in variable
iscomponentdataexists = 'device_ids' in validated_data
if iscomponentdataexists :
componentdata= validated_data.pop('device_ids')
instance = super().update(instance, validated_data) # Update Monitor Data
# looping through new device_ids list
if iscomponentdataexists :
for deviceid in componentdata:
try:
obj = coreModel.Component.objects.get(id=deviceid)
instance.devices.add(obj)
except coreModel.Component.DoesNotExist:
pass
instance.save()
return instance
Remove read_only=True from device

How to pass data to serializers in django

I want to pass user_id from view to serializer
I have model Answer
class Answer(models.Model) :
text = models.CharField(max_length=500)
question_id = models.CharField(max_length=25)
user_id = models.CharField(max_length=25, default=1)
This is my Serializer
class CreateAnswer(generics.CreateAPIView) :
def get_serializer_context(self):
context = super().get_serializer_context()
context["id"] = self.request.user.id
return context
serializer_class = AnswerQuestionSerializer
queryset = Answer.objects.all()
What I need to write in my view to take user_id and create model with this user_id ?
You can override the perform_create method & pass the user_id field to save method of the serializer.
class CreateAnswerView(generics.CreateAPIView) :
serializer_class = AnswerQuestionSerializer
def perform_create(self, serializer):
serializer.save(user_id=self.request.user.id)
You can use serializers.Hiddenfield to get current user in serializer class
https://www.django-rest-framework.org/api-guide/fields/#hiddenfield
There are multiple ways to do this task. One of them is to override create in your serializer.
Following is the code snippet:
class BlogSerializer(serializers.Serializer):
def create(self, validated_data):
user = self.context['request'].user
blog = Blog.objects.create(
user=user,
**validated_data
)
return blog
Explanation: A context is passed to the serializer which contains the request by default. So you can access the user easily with self.context['request'].user

How to add new field to filtered query

I'm trying to add a new column for which I need to do some operations based on other models in a FilterSet.
I have my view like this:
class FilteredListView(ListView):
filterset_class = None
def get_queryset(self):
queryset = super().get_queryset()
self.filterset = self.filterset_class(self.request.GET, queryset=queryset)
return self.filterset.qs.distinct()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filterset'] = self.filterset
querysetPaises = Pais.objects.all().filter(paisActivo=1).order_by('nombrePais')
context['paises']=querysetPaises
return context
class ListadoPartnerView(FilteredListView):
filterset_class = PartnerFilter
paginate_by = 10
model = IngresosPersonas
fields = ['idPlataforma', 'number_plataforma', 'contactoinfo']
template_name = 'usuarios/listadoPartners.html'
And my filter is:
class PartnerFilter(django_filters.FilterSet):
class Meta:
model = IngresosPersonas
fields = ['idPlataforma', 'number_plataforma']
Basically I want to include a new column on the filterset that the template receives which is not included in the model.
I've tried to access the filterset.qs but no luck
Many thanks
You can add non model field to FilterSet but you need manually specify method which will be triggered by this filter:
class PartnerFilter(django_filters.FilterSet):
new_field = django_filters.CharFilter(method="filter_new_field")
class Meta:
model = IngresosPersonas
fields = ['idPlataforma', 'number_plataforma', 'new_field']
def filter_new_field(self, queryset, name, value):
return queryset.filter() # your extra filters here
If you need to add non model field on representation level (template) you can just define property in your model:
class MyMode(models.Model):
#property
def new_field(self):
return "some value"
In template you can access this field like this {{ obj.new_field }}.

How to find object by its id in Django Rest Framework

I can't have object by its id in Django Rest Framework. I have a such model:
class BlogPost(models.Model):
title = models.CharField(max_length=128)
content = models.TextField()
created = models.DateTimeField(auto_now_add=True)
Then I write a serializer:
class BlogPostSerializer(serializers.ModelSerializer):
class Meta:
model = BlogPost
fields = ('title', 'content', 'created')
In my views.py I have this:
class BlogPostListFilter(dajngo_filter.FilterSet):
blog_post_id = django_filters.NumerFilter(name = 'id')
class Meta:
model = BlogPost
fiields = ['blog_post_id']
class BlogPostList(generics.ListCreateAPIView):
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
permission_classes = (AllowAny,)
filter_class = BlogPostListFilter
paginate_by = 100
And such code in my urls:
url(r'^blogpost/$', ListCreateAPIView.as_view(model=BlogPost), name='blogpost-list'),
But when I write in browser http://example.com/blogpost/?blog_post_id=1 I have all objects
If you really want to use ListCreateAPIView. You need to make some changes:
urls.py:
url(r'^blogpost/(?P<post_id>\w+)$', views.BlogPostList.as_view(),name='blogpost-list'),
views.py
class BlogPostList(generics.ListCreateAPIView):
serializer_class = BlogPostSerializer
permission_classes = (AllowAny,)
filter_class = BlogPostListFilter
paginate_by = 100
def get_queryset(self):
queryset = BlogPost.objects.filter(pk=self.kwargs['post_id'])
return queryset
But I think that Django Rest Framework provides better Class Based Views for your use case, such as RetrieveAPIView. As far as I understand, it seems that you just want to get an object, and this generic view is for a list of objects.
In my case, I stumbled upon this question looking to access the object id while overriding a ModelViewSet's retrieve method. After some research and experimentation, I discovered that the object id is stored in a dictionary called self.kwargs in the 'pk' key.
I am using djangorestframework==3.11.0.
class MealItemViewSet(viewsets.ModelViewSet):
queryset =MyModel.objects.all()
serializer_class = serializers.MyModelSerializer
def retrieve(self, request, *args, **kwargs):
# The Primary Key of the object is passed to the retrieve method through self.kwargs
object_id = self.kwargs['pk']
I hope this answer helps another forlorn StackOverflow wanderer at some point!

Categories