self.request.user does not work in Django REST framework - django

I want to give only the information of the user who requested with self.request.user, but for some reason, this way I get the information of all users.
How can I improve this so that we can retrieve only the information of the user who requested it?
Please let me know if you know anything about this.
View
class StatisticsViewSet(APIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = EntrySerializer
def get(self, request):
queryset = self.request.user.entries.all()
serializer = StatisticsSerializer(queryset)
return Response(serializer.data)
Serializer
class StatisticsSerializer(serializers.Serializer):
daily_report = serializers.SerializerMethodField()
daily_report_week = serializers.SerializerMethodField()
def get_daily_report(self, obj):
data = Entry.objects.filter(user=obj.user).values(
'created_at__year', 'created_at__month',
'created_at__day').annotate(Sum('time')).order_by(
'created_at__year', 'created_at__month', 'created_at__day')
........
...
...
Model
class Entry(models.Model):
project = models.ForeignKey(Project,
related_name='entries',
on_delete=models.CASCADE)
time = models.IntegerField(default=0)
user = models.ForeignKey(User,
related_name='entries',
on_delete=models.CASCADE)
created_at = models.DateTimeField(default=datetime.now)
def __str__(self):
return '%s - %s' % (self.project.name, self.created_at)

You can filter the queryset inside the serializer using the context
Serializer:
class StatisticsSerializer(serializers.Serializer):
daily_report = serializers.SerializerMethodField()
daily_report_week = serializers.SerializerMethodField()
def get_daily_report(self, obj):
user = self.context['request'].user
data = Entry.objects.filter(user=user).values(
'created_at__year', 'created_at__month',
'created_at__day').annotate(Sum('time')).order_by(
'created_at__year', 'created_at__month', 'created_at__day')
View:
class StatisticsViewSet(APIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = EntrySerializer
def get(self, request):
queryset = self.request.user.entries.all()
serializer = StatisticsSerializer(queryset, context = {'request': self.request)
return Response(serializer.data)

Related

How can I update specific field after retrieved in django rest framework

How can I update specific field after retrieved in django rest framework
# Models.py
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
view = models.IntegerField(default=0)
def __str__(self):
return self.title
I want to update view after read a specific data.
# Views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Update view + 1
# serializers.py
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
Please help me
If you want your field to be incremented only on a GET request, you can update it in the retrieve method:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.view = instance.view + 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
If you want it to be incremented with both GET and PATCH, you could update it in get_object instead:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_object(self):
instance = super(ArticleDetail, self).get_object()
instance.view = instance.view + 1
instance.save()
return instance

DRF: django rest framework case insensitive lookup in detail view

How to make urls case insensitive with certain parameters passed
For example, assuming Stock model has a ticker. All links below should find the same ticker content, right now they are case sensitive and try to search for different values:
/stocks/AAPL
/stocks/aapl
/stocks/AaPl
views.py
class StockViewSet(viewsets.ModelViewSet):
queryset = Stock.objects.all()
serializer_class = StockSerializer
lookup_field = "ticker"
#action(detail=True, methods=["get"], url_path="is", url_name="is")
def get_income_statement(self, request, *args, **kwargs):
is_qs = IncomeStatement.objects.filter(ticker=self.get_object())
serializer = IncomeStatementSerializer(is_qs, many=True)
return Response(serializer.data)
#action(detail=True, methods=["get"], url_path="bs", url_name="bs")
def get_balance_sheet(self, requests, *args, **kwargs):
bs_qs = BalanceSheet.objects.filter(ticker=self.get_object())
serializer = BalanceSheetSerializer(bs_qs, many=True)
return Response(serializer.data)
#action(detail=True, methods=["get"], url_path="cf", url_name="cf")
def get_cashflows_statement(self, requests, *args, **kwargs):
cf_qs = CashflowsStatement.objects.filter(self.get_object())
serializer = CashflowsStatementSerializer(cf_qs, many=True)
return Response(serializer.data)
class IncomeStatementDetail(viewsets.ModelViewSet):
queryset = IncomeStatement.objects.all()
serializer_field = IncomeStatementSerializer
class BalanceSheetDetail(viewsets.ModelViewSet):
queryset = BalanceSheet.objects.all()
serializer_field = BalanceSheetSerializer
class CashflowsStatementDetail(viewsets.ModelViewSet):
queryset = CashflowsStatement.objects.all()
serializer_field = CashflowsStatementSerializer
urls.py
router = DefaultRouter()
router.register(r"stocks", views.StockViewSet)
urlpatterns = router.urls
models.py
class Stock(models.Model):
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
ticker = models.CharField(max_length=10, unique=True, primary_key=True)
slug = models.SlugField(default="", editable=False)
def save(self, *args, **kwargs):
value = self.ticker
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
def __str__(self):
return self.ticker
class Meta:
verbose_name = "stock"
verbose_name_plural = "stocks"
ordering = ["ticker"]
Use lookup_url_kwarg and lookup_field as
from rest_framework import viewsets
class StockViewSet(viewsets.ModelViewSet):
lookup_url_kwarg = 'ticker'
lookup_field = 'ticker__iexact'
# rest of your code
You can refer the source code of get_object(self) to see how DRF fetching the model object in the detail view.

Django RF, validation of input data in view layer

I wanted to get the date or tablerequireDate argument from the POST requests, how do I achieve in the below view layer ?
VIEWS.PY
class Tablecreateview(generics.CreateAPIView):
queryset = Tables.objects.all()
serializer_class = Tableserializer
def perform_create(self, serializer):
request_user = self.request.user
serializer.save(author=request_user)
MODELS.PY
class Tables(models.Model):
tablerequiretime = models.TimeField()
tablerequireDate = models.DateField()
created = models.DateTimeField(auto_now=True)
updatedat = models.DateTimeField(auto_now_add=True)
foodliketoeat = models.CharField(max_length=200)
totalpersons = models.PositiveIntegerField(
default=0, validators=[MinValueValidator(0), MaxValueValidator(20)])
author = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.author.username
SERIALIZERS.PY
class Tableserializer(serializers.ModelSerializer):
class Meta:
model = Tables
exclude=('author',)
Okay you can access this field before perform_create takes place
class Tablecreateview(generics.CreateAPIView):
queryset = Tables.objects.all()
serializer_class = Tableserializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
tablerequireDate = serializer.data['tablerequireDate']
# Do you magic then perform creation
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Another Round of a solution
class Tableserializer(ModelSerializer):
class Meta:
model = Tables
exclude=('author',)
def validate_tablerequireDate(self, data):
try:
# do validation
except ValidationError:
raise Validation.....
else:
return validated_data

Call for model field validation in the serializer

I will try to make a check for the uniqueness of the field at the validation level in the serializer and can not understand why the validator is not called at all.
models.py
class Vendor(models.Model):
active = models.BooleanField(default=False)
...
class VendorContacts(models.Model):
vendor = models.ForeignKey('Vendors', related_name='contacts', on_delete=models.CASCADE)
email = models.CharField(max_length=80, blank=True, null=True)
.....
serializer.py
class VendorContactCreateSerializer(serializers.ModelSerializer):
email = serializers.CharField(validators=[RegexValidator(regex=r'[^#]+#[^\.]+\..+',
message='Enter valid email address')])
vendor = serializers.PrimaryKeyRelatedField(queryset=Vendors.objects.all(), required=False, allow_null=True)
class Meta:
model = VendorContacts
fields = (.....
)
def create(self, validated_data):
.....
#some logic
def validate_email(self, value):
print('Start validation')
exist_contact = VendorContacts.objects.filter(email=value)
if exist_contact:
vc = get_object_or_404(VendorContacts, email=value)
v = vc.vendor
if v.active:
raise serializers.ValidationError('Email {} already exists'.format(value))
return value
In the above serializer, I perform a check at the def validate_email() model field level.
print('Start validation') is not called.
I tried the same at the object level through def validate(): but it is not called either.
UPD
views.py
class VendorContactsCreateView(APIView):
permission_classes = [permissions.AllowAny, ]
serializer_class = VendorContactCreateSerializer
def post(self, request, *args, **kwargs):
data = request.data
serializer = VendorContactCreateSerializer(data=data)
try:
serializer.is_valid(raise_exception=True)
serializer.save()
except ValidationError:
return Response({"errors": (serializer.errors,)},
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(request.data, status=status.HTTP_200_OK)

implementing notification on a django rest api

While building my API, I didn't think about the logic behind notifications. Please, How do I solve a problem like this on a potentially big project? let us assume I have the code below:
model.py
class Showcase(models.Model):
title = models.CharField(max_length=50)
description = models.TextField(null=True)
skill_type = models.ForeignKey(Skill, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, related_name="Showcases")
content = models.TextField(null=True)
created_on = models.DateTimeField(auto_now=True)
updated_on = models.DateTimeField(auto_now_add=True)
voters = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="upvotes")
slug = models.SlugField(max_length=255, unique=True)
serializer.py
class ShowcaseSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True)
created_on = serializers.SerializerMethodField(read_only=True)
likes_count = serializers.SerializerMethodField(read_only=True)
user_has_voted = serializers.SerializerMethodField(read_only=True)
slug = serializers.SlugField(read_only=True)
comment_count = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Showcase
exclude = ['voters', 'updated_on']
def get_created_on(self, instance):
return instance.created_on.strftime("%d %B %Y")
def get_likes_count(self, instance):
return instance.voters.count()
def get_user_has_voted(self, instance):
request = self.context.get("request")
return instance.voters.filter(pk=request.user.pk).exists()
def get_comment_count(self, instance):
return instance.comments.count()
view.py
# SHOWCASE APIView
class showcaseCreateViewSet(generics.ListCreateAPIView):
'''
Create showcases view. user must be logged in to do this
'''
queryset = Showcase.objects.all()
serializer_class = ShowcaseSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class ShowcaseLikeAPIView(APIView):
'''
Can like(post) and unlike(delete) the showcases, must be
authenticated to do this
'''
serializer_class = ShowcaseDetaiedSerializer
permission_classes = [IsAuthenticated]
def delete(self, request, slug):
showcase = get_object_or_404(Showcase, slug=slug)
user = self.request.user
showcase.voters.remove(user)
showcase.save()
serializer_context = {"request": request}
serializer = self.serializer_class(showcase, context=serializer_context)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request, slug):
showcase = get_object_or_404(Showcase, slug=slug)
user = self.request.user
showcase.voters.add(user)
showcase.save()
serializer_context = {"request": request}
serializer = self.serializer_class(showcase, context=serializer_context)
return Response(serializer.data, status=status.HTTP_200_OK)
with the code above that likes a user's post(Showcase), I am trying to figure out how the user can get notified when a user likes his post.
and the things I am considering for the notification, the user that gets notified, the user that makes the action, the post(in this case showcase) that is getting the action, the message that gets passed, a boolean field for if it has been read. The method that comes to my head is creating an app for that but after nothing else. please, how do I solve a problem like this, or what is the best/recommended way to solve this?