Django Rest Framework DELETE request responds like a GET request - python-3.x

I'm trying to delete an entry in my data base that is returned by a modelviewset get_queryset. When sending a DELETE request through the DRF web interface and via postman, I receive this response "DELETE /api/remove_self/3 HTTP/1.1" 200 along with the data I am trying to delete. The code that gives this result looks like this:
Models.py
class EventAtendee(models.Model):
"""Lists users atending an event"""
#below connects user profile to event
id = models.AutoField(primary_key=True)
event_id = models.IntegerField(null = True)
user_profile = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
def __str__(self):
return self.event_id
views.py
class RemoveSelfFromEvent(viewsets.ModelViewSet):
"""Remove Yourself From an Event you were attending"""
authentication_classes = (TokenAuthentication,)
serializer_class = serializers.EventAtendeeSerializer
permission_classes = (permissions.UpdateOwnStatus, IsAuthenticated)
def perform_create(self, serializer):
"""Sets the user profile to the logged in user"""
#
serializer.save(user_profile=self.request.user)
def get_queryset(self):
"""
This view should return a list of all the purchases for
the user as determined by the username portion of the URL.
"""
#user_profile = self.kwargs['user_profile']
event_id = self.kwargs['event_id']
return models.EventAtendee.objects.filter(event_id=event_id, user_profile=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
urls.py
router = DefaultRouter(trailing_slash=False)
router.register('events', views.EventAtendeeViewSet, basename='EventAtendee')
urlpatterns = [
path('remove_self/<event_id>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'list'})),
]
Any help is much appreciated!

You are mapping the method DELETE to list in your urls.
path('remove_self/<event_id>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'list'})),
Correct way to do:
path('remove_self/<pk>', views.RemoveSelfFromEvent.as_view({'get': 'list', 'delete': 'destroy'})),
mapping of various methods:
POST : create
GET : retrieve
PUT : update
PATCH : partial_update
DELETE : destroy

Related

Django Create or update with unique together values

I'm trying to make an attendance system in the frontend I retrieve a list of users which the request.user can take attendance of, I'm using CreateAPIView but this won't get me the desired effect as I want the request.user to be able to toggle between Absent, Present, and on_leave even after the entry has been created on the first request
i have seen questions and answers about create or update here but i couldn't use them so any help would be appriciated
this is my view.py
class AttendanceListCreateAPIView(CreateAPIView):
permission_classes = [IsTeacher_Student]
queryset = Attendance.objects.all()
serializer_class = AttendanceSerializer
def post(self, request, *args, **kwargs):
user = request.user
data = request.data
serializer = AttendanceSerializer(data=data)
if serializer.is_valid():
data_user = serializer.validated_data['user']
## validation
return Response({"message": "Something is wrong, maybe you have already taken attendance for this user"},
status=status.HTTP_400_BAD_REQUEST)
my serializer.py
class AttendanceSerializer(serializers.ModelSerializer):
date = serializers.HiddenField(default=timezone.now)
leave_reason = serializers.CharField(required=False, default="")
class Meta:
model = Attendance
fields = ['user', 'presence', 'leave_reason', 'date']
extra_kwargs = {
'user': {'required': True},
'presence': {'required': True},
'leave_reason': {'required': False},
}
validators = [
UniqueForYearValidator(
queryset=Attendance.objects.all(),
field='user',
date_field='date',
message=("You have already taken the attendance")
)
]
def create(self, validated_data):
instance = Attendance.objects.create(
user=validated_data['user'],
presence=validated_data['presence'],
leave_reason=validated_data['leave_reason'],
date=validated_data['date'],
)
instance.save()
return instance
desired effect
the user fk and date are unique together meaning that if the date isn't unique for the user update it if it is create a new entry

Django Rest Framework Field Validation Issue

My subscription view is located inside of UserViewSet. I'm wondering why I'm getting
IntegrityError at /api/users/1/subscribe/
new row for relation "users_subscription" violates check constraint "prevent_self_subscription"
DETAIL: Failing row contains (11, 1, 1).
instead of proper json answer. Somehow SubscriptionSerializer field validation doesnt wish to work. Any thoughts?
models.py
class Subscription(models.Model):
user = models.ForeignKey(
User, related_name='subscriber',
on_delete=models.CASCADE)
author = models.ForeignKey(
User, related_name='subscribing',
on_delete=models.CASCADE)
class Meta:
constraints = [
models.UniqueConstraint(
fields=('user', 'author'),
name='unique_subscription'
),
models.CheckConstraint(
check=~models.Q(user=models.F('author')),
name='prevent_self_subscription'
)
]
serializers.py
class SubscriptionSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(
read_only=True, default=serializers.CurrentUserDefault())
class Meta:
model = models.Subscription
fields = ('author', 'user', )
validators = [
serializers.UniqueTogetherValidator(
queryset=models.Subscription.objects.all(),
fields=['author', 'user', ]
)
]
def create(self, validated_data):
return models.Subscription.objects.create(
user=self.context.get('request').user, **validated_data)
def validate_subscribing(self, value):
if self.context.get('request').user == value:
raise serializers.ValidationError(
'You cant subscribe to yourself!')
return value
views.py
#action(['post'], detail=True)
#permission_classes(permissions.IsAuthenticated)
def subscribe(self, request, *args, **kwargs):
author = get_object_or_404(models.User, id=kwargs['id'])
data = request.data.copy()
data.update({'author': author.id})
serializer = serializers.SubscriptionSerializer(
data=data, context={'request': request})
if request.method == 'POST':
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(
status=status.HTTP_201_CREATED,
data=self.get_serializer(author).data)
It was the wrong method name, field name is 'author' and method was validate_subscribing() instead of validate_author().

List Class View didn't return an HttpResponse

I've been trying to get a class-based list view to display all entries under a user's account (applicant), but when loading the page I'm given the following error:
The view jobassessment.views.view didn't return an HttpResponse object. It returned None instead.
To me that sounds like the URL dispatcher isn't running the correct view, but this is my URL file for both the whole site and the jobassessment application and I can't seem to spot the fault.
Site URL.py:
urlpatterns = [
path('admin/', admin.site.urls, name="admin"),
path('accounts/', include('django.contrib.auth.urls'), name="accounts"),
path('applicant/', include('userprofile.urls'), name="applicant"),
path('assessments/', include('jobassessment.urls')),
]
JobAssessment App's URL.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.AssessmentListView.as_view(), name="assessment"),
]
This is my ListView that is called:
class AssessmentListView(LoginRequiredMixin, generic.ListView):
model = Assessment
template_name ='assessments_index.html'
paginate_by = 5
def get(self, request, *args, **kwargs):
# Ensure they have first created an Applicant Profile
if not Applicant.objects.filter(user=self.request.user).exists():
messages.info(request, "You must create a profile before you can view any assessments.")
return redirect('profile_create_form')
def get_queryset(self):
return Assessment.objects.all().filter(applicant=Applicant.objects.filter(user=self.request.user)).order_by('-assessment_stage')
If Applicant of current login user not exists then your if condition fails and since there is no else
part in there so there is no HttpResponse returned from the view. So please add else part if applicant exists and return HttpResponse()
class AssessmentListView(LoginRequiredMixin, generic.ListView):
model = Assessment
template_name ='assessments_index.html'
paginate_by = 5
def get(self, request, *args, **kwargs):
# Ensure they have first created an Applicant Profile
if not Applicant.objects.filter(user=self.request.user).exists():
messages.info(request, "You must create a profile before you can view any assessments.")
return redirect('profile_create_form')
else:
return HttpResponse() #<------ add corresponding HttpResponse if Applicant exists.
def get_queryset(self):
return Assessment.objects.all().filter(applicant=Applicant.objects.filter(user=self.request.user)).order_by('-assessment_stage')
Following the django document on ListView filter it's better to handle it within get_queryset. So for your case it would be something like this:
class AssessmentListView(LoginRequiredMixin, generic.ListView):
model = Assessment
template_name ='assessments_index.html'
paginate_by = 5
def get_queryset(self):
# Ensure they have first created an Applicant Profile
if not Applicant.objects.filter(user=self.request.user).exists():
messages.info(request, "You must create a profile before you can view any assessments.")
return redirect('profile_create_form')
else:
return Assessment.objects.all().filter(applicant=Applicant.objects.filter(user=self.request.user)).order_by('-assessment_stage')

how to get a string parametr in drf modelviewset

i need to use a path with an optional paramentr, to specify a user via a srting a request would look like 'api/users/specific_username' or 'api/users' for all users
urls:
router = DefaultRouter()
router.register(r'users', MyUserViewSet, basename='user-me')
views:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
def get_queryset(self):
queryset = User.objects.all()
if self.kwargs['username']:
username=self.request.GET.get('username')
queryset = User.objects.filter(username=username)
return queryset
username=self.kwargs['username']
returns KeyError
username=self.request.GET.get('username')
returns None
I've managed to achieve that by doing like so:
so for request that looks like so:
http://example.com/api/viewset?username=denvercoder9
the code will look this:
def get_queryset(self):
"""
Optionally restricts the returned purchases to a given user,
by filtering against a `username` query parameter in the URL.
"""
queryset = Purchase.objects.all()
username = self.request.query_params.get('username', None)
if username is not None:
queryset = queryset.filter(purchaser__username=username)
return queryset
or if you really want you override the retrieve:
(haven't tested this code)
def retrieve(self, request, pk=None):
queryset = User.objects.filter(username=pk)
contact = get_object_or_404(queryset, pk=1)
serializer = ContactSerializer(contact)
return Response(serializer.data)

How to implement django admin queryset filter with from extended user model class

I have extended Django default User model (just to save user state_id) class with following model.
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,)
state_id = models.IntegerField(blank=False)
def __str__(self):
return self.user.username
And now I want to filter the data by logged user's state_id. I tried to implement queryset filter but it does not do anything.
class VisVisitsAdmin(admin.ModelAdmin):
list_per_page = 10
list_display = ('visit_id','visit_no','user_name','mobile_number','program_name','state_name','district_name','block_name','school_name',)
list_filter = ('date_of_visit',)
def queryset(self, request):
qs = super(VisVisitsAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(state_id=request.user.UserProfileInfo.state_id)
def state_name(self, obj):
if obj.school_program:
return obj.school_program.school.cluster.block.district.state.name_of_state
state_name.short_description = 'state name'
You are trying to fetch the state_id from the userprofileinfo instance related to user object.
Everything seems fine but the instance is available as userprofileinfo and not UserProfileInfo , so change qs as :
qs.filter(state_id=request.user.userprofileinfo.state_id)

Resources