Django how to append current logged in user to request.data - django

How do I append current logged in user to request.data when making post call to create a new chat. I tried append it to the request.data but its a querydict and immutable
// models.py
class ChatLog(models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
participants = models.ManyToManyField(Profile, related_name='chatlogs')
def __str__(self):
return str(self.id)
class Message(models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
chat_log = models.ForeignKey(ChatLog, on_delete=models.CASCADE, related_name='messages')
sender = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='sentmessages')
body = models.TextField()
is_read = models.BooleanField(default=False, null=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id)
class Meta:
ordering = ['-created']
// views.py
class ChatList(generics.ListCreateAPIView):
serializer_class = ChatSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
user = self.request.user.profile
return user.chatlogs.all()
def post(self, request, *args, **kwargs):
serializer = ChatSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

The ListCreateAPIView specifically has the perform_create method you can override. By default it just does:
def perform_create(self, serializer):
serializer.save()
You can override that to add additional data to the serializer for example:
def perform_create(self, serializer):
serializer.save(sender=self.request.user)
Get rid of your post method, you're just overriding and repeating the automagic for which you're using generic views in the first place.

Related

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

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)

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?

Django Rest Framework: How to associate the object with the user when posting the object

I'm new to creating REST API so I might misunderstand something.
I'm creating REST API using Django Rest Framework. And I'm trying to create an object and send it from my mobile app.
However, API returns 400. I think it still cannot associate the object with the request user and I'm wondering how to do it.
models.py
class Item(models.Model):
item_name = models.CharField()
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
serializers.py
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('item_name', 'created_by')
and views.py
class ListItems(generics.ListCreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
What I want to know is how to associate the object with the request user when posting the object like as we do like
if form.is_valid():
item = form.save(commit=False)
item.created_by = request.user
item.save()
I think the easiest approach is like this:
class ItemSerializer(serializers.ModelSerializer):
created_by = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
Reference can be found here
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('item_name',)
class ListItems(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
you can do this way
One of the possible way to overwrite serializer_create method. As user is not associated with request.data first we need to make sure, this is write_only field and also need to assign current user from modelSerializer's self.context.request.user. Following addition should solve the problem.
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('item_name', 'created_by')
extra_kwargs = {'created_by': {'write_only': True}}
def create(self, validated_data):
item = Item(
item_name=validated_data['item_name'],
created_by=self.context.request.user
)
item.save()
return item
Reference link
It works for me
models.py
class Category(models.Model):
name = models.CharField('Category', max_length=200, unique=True, help_text='Name of the category')
slug = models.SlugField('Slug', max_length=100, db_index=True, unique=True, help_text='Name of the category in format URL')
def __str__(self):
return (self.name)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
serializers.py
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = [
'id', 'name', 'slug'
]
read_only_fields = [
'slug',
]
Finally, I get the user in the view, before to save the post.
views.py
class CategoryList(APIView):te a new category instance.
permission_classes = (IsAuthenticatedOrReadOnly,)
def get(self, request, format=None):
categories = Category.objects.all()
serializer = CategorySerializer(categories, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request, format=None):
serializer = CategorySerializer(data=request.data)
if serializer.is_valid():
serializer.save(created_by=self.request.user)
Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)