Get user's last message django-postman & Rest API - python

I've been install Django-Postman user to user messaging package. I'm trying to get user's last message with Rest API.
You can check django-postman package on here: https://pypi.org/project/django-postman/
A part of models.py
class Message(models.Model):
"""
A message between a User and another User or an AnonymousUser.
"""
SUBJECT_MAX_LENGTH = 120
subject = models.CharField(_("subject"), max_length=SUBJECT_MAX_LENGTH)
body = models.TextField(_("body"), blank=True)
sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='sent_messages',
null=True, blank=True, verbose_name=_("sender"))
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='received_messages',
null=True, blank=True, verbose_name=_("recipient"))
sent_at = models.DateTimeField(_("sent at"), default=now)
objects = MessageManager()
Views.py
class InboxLastMessagesViewSet(viewsets.ModelViewSet):
serializer_class = InboxLastMessagesSerializer
authentication_classes = (JSONWebTokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
return Message.objects.filter(Q(sender=user) | Q(recipient=user)).order_by('sender')
Serializers.py
class InboxLastMessagesSerializer(serializers.ModelSerializer):
senderusername = serializers.CharField(source='sender.username', read_only=True)
reciusername = serializers.CharField(source='recipient.username', read_only=True)
sonmesaj = serializers.SerializerMethodField()
def get_lastmessage(self, obj):
/// I'M TRYING TO CREATE A FUNCTION ON HERE FOR GET SENDER'S LAST MESSAGE ////
lastmsg = obj.latest('sent_at')
return dict(body=lastmsg)
class Meta:
model = Message
fields = ('senderusername', 'reciusername', 'body', 'sent_at', 'lastmessage')
I want to an output like this:
{
"senderusername": "user",
"reciusername": "user2",
"body": "Actually that is not last message",
"sent_at": "2019-01-19T23:08:54Z",
"lastmessage": {
"body": "That's conversation's last message!"
}
},
{
"senderusername": "user",
"reciusername": "user2",
"body": "I said that is not last message",
"sent_at": "2021-05-10T23:09:42Z",
"lastmessage": {
"body": "That's conversation's last message!"
}
},

You can get the last message like this:
def get_lastmessage(self, obj):
lastmsg = Message.objects.latest('sent_at')
data = {'senderusername': obj.senderusername,
'reciusername': obj.reciusername,
'body': lastmsg.body
'sent_at': lastmsg.sent_at
'last_message': {
'body': lastmsg.body
}
}
return data

Related

Creating and updating data from API answerI to Django REST project (MySQ)?

I have a Django REST project. I have a models User, Store and Warehouse.
And I have a module with marketplace parser, that gets data from marketplace API. In this module there is a class Market and a method "get_warehouses_list". This method returns a JSON with a STORE's warehouse list.
Examle answer:
{
"result": [
{
"warehouse_id": 1,
"name": "name1",
"is_rfbs": false
},
{
"warehouse_id": 2,
"name": "name2",
"is_rfbs": true
}
]
}
What I have to do is to make creating and updating methods to set and update this warehouse list into my MySQL DB (with creating an endpoint for setting and updating this data).
I don't know what is incorrect in my code, but when I send POST request to my endpoint in urls.py
router.register("", WarehouseApi, basename="warehouse")
I get 400 error instead of setting warehouse list into my DB.
My code:
user/models.py
class User(AbstractUser):
username = models.CharField(
max_length=150,
unique=True,
null=True)
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
unique=True,
editable=False)
store/models.py
`
class Store(models.Model):
user = models.ForeignKey(
User,
on_delete=models.PROTECT)
name = models.CharField(max_length=128,
blank=True)
type = models.PositiveSmallIntegerField(
choices=MARKET,
default=1,
verbose_name="Type API")
api_key = models.CharField(max_length=128)
client_id = models.CharField(max_length=128)
warehouses/models.py
class Warehouse(models.Model):
store = models.ForeignKey(
Store,
on_delete=models.СASCAD, null=True)
warehouse_id = models.BigIntegerField(
unique = True,
null = True)
name = models.CharField(
max_length=150)
is_rfbs = models.BooleanField(default=False)
`
serializers.py
`
class WarehouseSerializer(serializers.ModelSerializer):
class Meta:
model = Warehouse
fields = '__all__'
store = serializers.CharField(max_length=50)
warehouse_id = serializers.IntegerField()
name = serializers.CharField(max_length=100)
is_rfbs = serializers.BooleanField()
is_default_warehouse = serializers.BooleanField()
class WarehouseUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Warehouse
fields = ('name', 'is_rfbs',)
def save(self, **kwargs):
self.instance.name = self.validated_data["name"]
self.instance.is_rfbs = self.validated_data["is_rfbs"]
self.instance.save
returself.instance
views.py
class WarehouseApi(ModelViewSet):
def get_queryset(self):
return Warehouse.objects.filter(
store__user_id=self.request.user.pk)\
.order_by('-warehouse_id')
def get_serializer_class(self):
if self.request.method in ("PUT", "PATCH"):
return WarehouseUpdateSerializer
return WarehouseSerializer
def create(self, request, *args, **kwargs):
st = Store.objects.filter(user=self.request.user, # getting all stores with marketplace type = 1
type=1)
for e in st:
api = Market(api_key=e.api_key, # call parser class Market
client_id=e.client_id)
data = api.get_warehouses_list() # call Market's method 'get_warehouses_list'
if len(data['result']) > 0:
for wh in data['result']:
alreadyExists = Warehouse.objects.filter( # check if warehouses with such ID already exists
warehouse_id=wh.get(
'warehouse_id')).exists()
if alreadyExists:
return Response({'message':'Warehouse ID already exists'})
else:
wh_data = {
'warehouse_id': wh.get('warehouse_id'),
'name': wh.get('name'),
'is_rfbs': wh.get('is_rfbs')
}
Warehouse.objects.create(**wh_data)
warehouses = Warehouse.objects.filter(
marketplace=1, store__in=st).order_by(
'-warehouse_id')
s = WarehouseSerializer(warehouses, many=True)
return Response(status=200, data=s.data)
else:
return Response(status=400,
data={"Error": "Store has no warehouses"})
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
api = Market(api_key=instance.store.api_key,
client_id=instance.store.client_id)
warehouses = Warehouse.objects.filter(store__user_id=self.request.user,
store__type=1) # get all store's warehouses
if warehouses:
for warehouse in warehouses:
r = api.get_warehouses_list() # call Market's method 'get_warehouses_list'
if len(r['result']) > 0:
for wh in r['result']:
if serializer.validated_data["name"] != wh['name']:
instance.name = wh['name']
instance.save(['name'])
if serializer.validated_data["is_rfbs"] != wh['is_rfbs']:
instance.name = wh['is_rfbs']
instance.save(['is_rfbs'])
serializer = WarehouseUpdateSerializer(instance)
return Response(serializer.data, {
'status': status.HTTP_200_OK,
'message': 'Warehouse updated successfully'
})
else:
return Response({
'message': 'Store has no warehouses'
})
else:
return Response({
'message': 'There are no saved warehouses in DB'
})
`
The 400 Error might be caused by a number of reasons. Do you have any logging information you can provide? Either from the Python logs or using the browser developer tools?
In your own code you are returning a 400 code if the variable data is empty. Are you sure you are not hitting this validation?
If nothing turns up, I advise you to add some exception dealing and logging capabilities to your own code as it seems to be very unprotected and post that information here if needed.

can't send post data to api in django

i can't send post data to api using django rest framework. i used postman to send data only user part is adding to the database , the activity of user is rejecting . i can't figure out problem can anyone help me to solve this problem
sending post data to api
{
"name": "karen",
"username": "karen",
"timezone": "US/Samoa",
"activity_periods": [
{
"log_in": "2020-06-09T21:53:25.120897Z",
"log_out": null
},
{
"log_in": "2020-06-09T22:02:35.289891Z",
"log_out": null
},
{
"log_in": "2020-06-09T22:03:36.425212Z",
"log_out": null
}
]
}
but only the user data is stored the activity is ignored
like this
{
"name": "karen",
"username": "karen",
"timezone": "US/Samoa",
"activity_periods": []
}
how can i add activity data to user...?
models.py
class User(models.Model):
name = models.CharField(max_length=20)
username = models.CharField(max_length=20)
password = models.CharField(max_length=20)
timezone = models.CharField(max_length=32, choices=TIMEZONES, default='UTC')
def __str__(self):
return self.name
class Activity(models.Model):
user = models.ForeignKey(User, related_name="activity_periods",on_delete=models.CASCADE,null=True, blank=True)
log_in = models.DateTimeField(null=True, blank=True)
log_out = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.user.name
serializers.py
class ActivitySerializer(serializers.ModelSerializer):
class Meta:
model = Activity
fields = ['log_in', 'log_out']
class UserSerializer(serializers.ModelSerializer):
# Passing login Logout to User
activity_periods = ActivitySerializer(many=True, read_only=True)
class Meta:
model = User
fields = ['name', 'username','timezone', 'activity_periods']
views.py
class ActivityListView(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
name = "activity-list"
urls.py
path('rest/',views.ActivityListView.as_view())
how can i add activity data to user...?
In your UserSerializer, you have the following line:
activity_periods = ActivitySerializer(many=True, read_only=True)
Since read_only is set to True, when you POST data it will not be written to the database. Try setting it to False instead.

Add extra field in response output in DRF 3.0

I have the following models
class Restaurant(models.Model):
name_of_the_restaurant = models.CharField(max_length=30, blank=True)
opening_time = models.TimeField(auto_now=False, auto_now_add=False)
closing_time = models.TimeField(auto_now=False, auto_now_add=False)
And
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
city = models.CharField(max_length=30, blank=True)
country = models.CharField(max_length=30, blank=True)
postal_code = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
favourite_restaurant = models.ManyToManyField(Restaurant,
blank=True,
related_name='favourite_restaurant',
related_query_name='favourite_restaurant')
I have defined a serializer for Restaurant model which is mainly :
class RestaurantSerializer(serializers.ModelSerializer):
class Meta:
model = Restaurant
fields = '__all__'
Now in my ViewSet logic I am doing the following :
class RestaurantListView(generics.ListAPIView):
serializer_class = RestaurantSerializer
def get_queryset(self):
queryset = {'Error': 'Please pass valid url parameters'}
city = self.request.query_params.get('city', None)
postal_code = self.request.query_params.get('postalcode', None)
country = self.request.query_params.get('country', None)
if city is not None or postal_code is not None:
queryset = Restaurant.objects.filter(
Q(city=city) | Q(pincode=postal_code))
if country and city is not None and postal_code is None:
queryset = Restaurant.objects.filter(country=country, city=city)
return queryset
def get(self, request, format=None):
restaurant_qs = self.get_queryset()
ids_list = [restaurant.id for restaurant in restaurant_qs]
favourite_restaurant = is_favourite_restaurant(ids_list, self.request.user)
serializer = RestaurantSerializer(restaurant_qs, many=True)
return Response(serializer.data)
where is_favourite_restaurant is a custom function function which returns queryset of FAVOURITE restaurant(s) of a user. Now in the output for this GET request I am getting result as :
[
{
"id": 2,
"name_of_the_restaurant": "Aniket",
"opening_time": "14:08:33.413402",
"closing_time": "22:08:33.413414"
},
{
"id": 3,
"name_of_the_restaurant": "Aniket-1",
"opening_time": "14:13:37.656385",
"closing_time": "22:13:37.656397"
}
]
Whereas the desired output I want is to append an extra field is_favourite:true to that restaurant which user has previously marked favourite. And hence the output should be
[
{
"id": 2,
"name_of_the_restaurant": "Aniket",
"opening_time": "14:08:33.413402",
"closing_time": "22:08:33.413414",
"is_favourite": true,
},
{
"id": 3,
"name_of_the_restaurant": "Aniket-1",
"opening_time": "14:13:37.656385",
"closing_time": "22:13:37.656397"
}
]
EDIT :
Definition of is_favourite_restaurant function :
def is_favourite_restaurant(restaurant_qs, user):
favourite_restaurant_qs = Profile.objects.get(user=user).favourite_restaurant.filter(
pk__in=restaurant_qs.values_list('id', flat=True))
return favourite_restaurant_qs
You can use SerializerMethodField. SerializerMethodField allows add extra field which is read only as you want.
class RestaurantSerializer(serializers.ModelSerializer):
is_favorite = serializers.SerializerMethodField()
class Meta:
model = Restaurant
fields = ('your', 'fields', 'is_favorite')
def get_is_like(self, obj):
return is_favourite_restaurant(obj.id, self.context['request'].user)
Normally, ListAPIView add context to serializer. As you use your create method, you should add manually.
serializer = RestaurantSerializer(restaurant_qs, many=True, context={'request': self.request})
Context allows access some data which is we send from the view.
As you did not shown your is_favourite_restaurant, i can't say that what should you do in that function. I guess you should change ids parameter from array to one id.
Your response looks like
[
{
"id": 2,
"name_of_the_restaurant": "Aniket",
"opening_time": "14:08:33.413402",
"closing_time": "22:08:33.413414",
"is_favourite": True,
},
{
"id": 3,
"name_of_the_restaurant": "Aniket-1",
"opening_time": "14:13:37.656385",
"closing_time": "22:13:37.656397",
"is_favourite": False,
}
]
def is_favourite_restaurant(restaurant_id, user):
favourite_restaurant_qs = Profile.objects.get(user=user).favourite_restaurant.filter(
pk=restaurant_id).exists()
return favourite_restaurant_qs

Populating json from multiple django models

I have the following 2 Django models, Lessons and UserLessons.
Lessons would be created by an admin and UserLessons is basically when a user is in progress with the Lesson or completed the Lesson, linked by a foreign key. UserLesson doesn't necessarily contain a Lesson entry, till the user actually starts with that specific one.
As I'm building an API (with DRF), I need to list the full list of all Lessons - easy.
LessonList = Lesson.objects.all().values('id', 'title')
This returns
[
{
"id": 1,
"title": "Lesson 1"
},
{
"id": 2,
"title": "Lesson 2"
},
{
"id": 3,
"title": "Lesson 3"
}
]
However, I need to be able to merge it with UserLesson (eg UserLessonList = UserLesson.objects.filter(user=request.user).values('id', 'lesson__id', 'completed') which currently returns
[
{
"id": 2,
"lesson__id": 1,
"completed": true
},
{
"id": 3,
"lesson__id": 2,
"completed": true
}
]
Ideally, it should return all the lessons from the db, and the the completed values, defaulting to completed: false if that specific lesson doesn't exist in DB.
Any suggestions?
Edit:
Views
class LessonList(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request):
LessonList = Lesson.objects.all().values('id', 'title')
UserLessonList = UserLesson.objects.filter(user=request.user).values('id', 'lesson__id', 'completed')
return Response(LessonList)
Models
class Lesson(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=250, verbose_name=u'Title')
slug = models.SlugField(null=True, blank=True, help_text='eg, lesson-1-whats-up')
published = models.BooleanField(default=False)
def __str__(self):
return(self.title)
class UserLesson(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE, null=True)
completed = models.BooleanField(default=False)
def __str__(self):
text = str(self.lesson.title)
return(text)
You should use ModelViewSet and serializers. Exactly ModelSerializer. Something like this:
class LessonSerializer(serializers.ModelSerializer):
completed = serializers.SerializerMethodField()
class Meta:
model = Lesson
fields = ['id', 'title', 'completed']
def get_completed(self, obj):
user = self.context.get('request').user
return UserLesson.objects.filter(user=user, lesson=obj, completed=True).exists()
class LessonViewSet(viewsets.ModelViewSet):
queryset = Lesson.objects.filter(published=True)
serializer_class = LessonSerializer
permission_classes = [IsAuthenticated]

How can I access django model property from view?

I have a django model:
class DebtRequest(models.Model):
from_user = models.ForeignKey(User, related_name='debt_requests_from_user')
to_user = models.ForeignKey(User, related_name='debt_requests_to_user')
paying_user = models.ForeignKey(User, related_name='debt_requests_paying_user')
receiving_user = models.ForeignKey(User, related_name='debt_requests_receiving_user')
amount = models.FloatField()
currency = models.CharField(max_length=10, default="USD")
description = models.CharField(max_length=100, blank=True)
date_incurred = models.DateTimeField(default=timezone.now)
deadline = models.DateTimeField()
payed = models.BooleanField(default=False)
overdue = models.BooleanField(default=False)
created = models.DateTimeField(default=timezone.now)
#property
def time_since_created(self):
return (timezone.now() - self.created).total_seconds()
Here is my view:
class ListDebtRequests(generics.ListAPIView):
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
debt_requests_list = Debt.objects.requests(user=request.user)
debt_requests_list_json = json.loads(serializers.serialize('json', debt_requests_list))
debt_requests_json = [debt_requests_json_format(x, request.user.id)
for x in debt_requests_list_json]
return JsonResponse(debt_requests_json, safe=False)
And here is the function debt_requests_json_format:
def debt_requests_json_format(x, user_pk):
fields = x["fields"]
# if == True --> Debt request addressed to current user.
if fields["to_user"] == user_pk:
return {"pk": x["pk"],
"time_since_created": fields["time_since_created"],
"created": fields["created"],
"is_user_to_user": True,
"current_user_pk": user_pk,
"from_user": fields["from_user"],
"from_user_first_name": User.objects.get(pk=fields["from_user"]).firstName,
"from_user_last_name": User.objects.get(pk=fields["from_user"]).lastName,
"paying_user": fields["paying_user"],
"receiving_user": fields["receiving_user"],
"amount": fields["amount"],
"currency": fields["currency"],
"payed": fields["payed"],
"description": fields["description"],
"date_incurred": fields["date_incurred"],
"deadline": fields["deadline"],
"overdue": fields["overdue"]}
else: # if == False --> Debt request has been sent by current user.
return {"pk": x["pk"],
"created": fields["created"],
"is_user_to_user": False,
"current_user_pk": user_pk,
"to_user": fields["to_user"],
"to_user_first_name": User.objects.get(pk=fields["to_user"]).firstName,
"to_user_last_name": User.objects.get(pk=fields["to_user"]).lastName,
"paying_user": fields["paying_user"],
"receiving_user": fields["receiving_user"],
"amount": fields["amount"],
"currency": fields["currency"],
"payed": fields["payed"],
"description": fields["description"],
"date_incurred": fields["date_incurred"],
"deadline": fields["deadline"],
"overdue": fields["overdue"]}
I need the model property to be accessed from within here ideally or pass it in to the function.
The time_since_created property returns the time in seconds since the model instance was created, however I don't know how to access this from my view.
How can I access this from my view?
I try define an example serializer for your model with extra field. This is very simple example.
class DebtRequestSerializer(serializers.ModelSerializer):
is_user_to_user = serializers.SerializerMethodField()
current_user_pk = serializers.SerializerMethodField()
time_since_created = serializers.IntegerField(source='time_since_created')
to_user_first_name = serializers.CharField(source='to_user.firstName')
class Meta:
model = DebtRequest
def get_is_user_to_user(self, obj):
return obj.to_user == self.context.get('request').user.id
def get_current_user_pk(self, obj):
return self.context.get('request').user.id
more details: rest-framework fields

Categories

Resources