I want to get session data in consumers.py, this session data will be used to filter data. The code like this.
queryset = Mail.objects.filter(status='session_data')
serializer_class = PostSerializer
permissions = permissions.AllowAny
async def connect(self, **kwargs):
await self.model_change.subscribe()
await super().connect()
#model_observer(Mail)
async def model_change(self, message, observer=None, **kwargs):
await self.send_json(message)
#model_change.serializer
def model_serialize(self, instance, action, **kwargs):
return dict(data=PostSerializer(instance=instance).data, action=action.value)
How can i get it ?
Related
My goal is to redirect the client to the chat session detail view if they are trying to open a new chat session with someone they already have a chat session with. Everything works fine but when I tried to open a duplicate chat session, it didnt get redirected and all what i got is a blank json response
//views.py
class ChatSessionListView(generics.ListCreateAPIView):
serializer_class = ChatSessionSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
return ChatSession.objects.filter(Q(initiator=self.request.user) | Q(receiver=self.request.user))
def perform_create(self, serializer):
receiver_username = self.request.data['username']
receiver = get_object_or_404(User, username=receiver_username)
chat_session = ChatSession.objects.filter(Q(initiator=self.request.user, receiver=receiver) | Q(initiator=receiver, receiver=self.request.user))
if chat_session.exists():
return redirect('v1:chat:chat_session_detail', session_id=chat_session[0].pk)
else:
serializer.save(initiator=self.request.user, receiver=receiver)
// urls.py
urlpatterns = [
path('', views.ChatSessionListView.as_view(), name='chat'),
path('<str:session_id>/', views.ChatSessionDetailView.as_view(), name='chat_session_detail')
]
You can not return a HTTP response in perform_create. perform_create is only supposed to create a new object with the serializer data: it creates a serializer with request.data, then checks if the serializer is valid, and then performs the create.
What you can do is override the create method:
class ChatSessionListView(generics.ListCreateAPIView):
serializer_class = ChatSessionSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self):
return ChatSession.objects.filter(Q(initiator=self.request.user) | Q(receiver=self.request.user))
def create(self, request, *args, **kwargs):
receiver = get_object_or_404(User, username=self.request.data['username'])
chat_sessions = ChatSession.objects.filter(
Q(initiator=self.request.user, receiver=receiver) |
Q(initiator=receiver, receiver=self.request.user)
)
chat_session = chat_sessions.first()
if chat_session is None:
serializer = ChatSessionSerializer(data=request.data)
if serializer.is_valid():
chat_session = serializer.save(initiator=self.request.user, receiver=receiver)
return redirect('v1:chat:chat_session_detail', session_id=chat_session.pk)
I got to know that we can override create method in order to send email but it's not working with my code.
views.py:
class FileUploadView(APIView):
parser_class = (MultiPartParser,)
def post(self, request, *args, **kwargs):
file_serializer = FileSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def create(self, request, *args, **kwargs):
response = super(FileUploadView, self).create(request, *args, **kwargs)
send_email() # sending mail
return response
def send_email(request):
email = EmailMessage(
'Title',
(FileSerializer.Fullname, FileSerializer.Email, FileSerializer.Contact),
'mymail#gmail.com',
['anothermail#gmail.com']
)
email.attach_file(FileSerializer.Upload)
email.send()
Help me in figuring out what's the problem here
Edit: APIView doesn't support create method, above code doesn't work
. I want to send the contents received from post method from rest API through a mail. Suggest me a proper method in order to do it with respect to above code.
APIView does not support create
You have got this part right. You want to send an email after the model object has been saved to database. Actually there are several ways to do that. You can do it from view, you can do it from your serializer, you can do it from your model, you can do it from a post_save signal hooked to your model. I am going to show you what was wrong with your code and then some of the other ways -
The corrections to be made in your code that, you could call the send_email function just after file_serializer.save() in your FileUploadView.post
class FileUploadView(APIView):
parser_class = (MultiPartParser,)
def post(self, request, *args, **kwargs):
file_serializer = FileSerializer(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
send_email() #sending Email
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def send_email(request):
email = EmailMessage(
'Title',
(FileSerializer.Fullname, FileSerializer.Email, FileSerializer.Contact),
'mymail#gmail.com',
['anothermail#gmail.com']
)
email.attach_file(FileSerializer.Upload)
email.send()
This process also calls the send_email function from view, but this view is a bit different. This view inherits from generics.CreateAPIView
from rest_framework import generics
class FileUploadView(generics.CreateAPIView):
serializer_class = FileUploadSerializer
parser_class = [MultiParser, ]
queryset = FileUploadModel.objects.all()
def perform_create(self, serializer):
serializer.save()
send_email()
You can call the send_email function from the create method of your seiralizer. You can override serializer.create method
class FileUploadSerializer(serializers.ModelSerializer):
class Meta:
model = FileUploadModel
fields = ['your', 'model', 'fields']
def create(self, validated_data):
instance = super(FileUploadSerializer, self).create(validated_data)
send_email()
return instance
Sending Email from your FileUploadModel model class. Here you override the save method of the model
class FileUploadModel(models.Model):
...your model fields definition...
def save(self, *args, **kwargs):
if not self.pk: #assuming we want to send email only when object is created first time in database
send_email()
super(FileUploadModel, self).save(*args, **kwargs)
On catch about overriding model.save method is that, it will not be called when you're performing bulk operations. Also it will be called every time you save the model i.e. both create and update that's why we added the pk check. This logic will send email before the object is inserted in your database if you want to send email only when the object is completely saved in database then do the following way with signals
You can hook a post_save signal to your model. In this way you send an email only after the object is saved in database
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=FileUploadModel)
def file_upload_post_save(sender, instance, **kwargs):
send_email()
Catch with using signals is that it will not be called when you do bulk operation.
I am assuming you're fairly new to the django enviornment. You should also have a look on celery to perform long running background tasks such as - sending emails.
I am using Django Rest Framework, currently to pull some data from the backend we are using Get request, but due to URL limit going high we are planning to implement a Post request. To do this firstly the backend Django Rest API has to be made available to serve a post request.
I am new to Django and I don't find a post or get method in the code, all i can say is we are using viewsets, I tried using "#detail_route(methods=['post'])" but this didn't work, what am I doing wrong here?
class XViewSet(viewsets.ViewSet):
renderer_classes = ''
def retrieve(self, request, pk=None):
try:
pk = int(pk)
except ValueError:
raise InvalidParameterError(parameter_name='id', invalid_value=pk)
queryset = models.X.objects.all()
x = get_object_or_404(queryset, pk=pk)
pipelines = request.query_params.getlist('pipeline[]')
callsets =
callset_ids =
serializer = serializers.XSerializer(x, context={'request': request})
requested_samples = [z[1:] for z in request.query_params.getlist('s')]
filtered_calls = []
serialized_data = serializer.data
unfiltered_calls = serialized_data.get('calls')
if unfiltered_calls:
for serialized_calls in unfiltered_calls:
if serialized_calls['callset'] in callset_ids:
unfiltered_calls = serialized_calls['data']
for call in unfiltered_calls:
if call['y'] in requested_y:
filtered_calls.append(call)
break
serialized_data['calls'] = filtered_calls
return Response(serialized_data, status=status.HTTP_200_OK)
def list(self, request):
qp = self.request.query_params
validated_qp =
# generate the query
query_object =
query =
# execute the query
cursor = connections['default'].cursor()
cursor.execute(query)
qs = utils.dictfetchall(cursor)
# sanitize query results
if 't' in validated_qp:
return_data =
else:
for x in qs:
if 'calls' in x:
x['calls'] =
else:
x['calls'] = {}
return_data =
resp = Response(return_data, status=status.HTTP_200_OK)
if validated_qp.get(''):
resp['content-disposition'] =
return resp
You can use class-based views to handle the requirements,
from rest_framework.views import APIView
class MyAPI(APIView):
def get(selfself, request):
# do stuff with get
return Response(data="return msg or data")
def post(self, request):
post_data = request.data
# do something with `post_data`
return Response(data="return msg or data")
UPDATE : Using ViewSet
ViewSet class provide us create() methode to create new model instances. So we can override that to handle post data coming to the view. Just add a create() under your view class as below
class XViewSet(viewsets.ViewSet):
renderer_classes = ''
def create(self, request): # Here is the new update comes <<<<
post_data = request.data
# do something with post data
return Response(data="return data")
def retrieve(self, request, pk=None):
# your code
return Response(serialized_data, status=status.HTTP_200_OK)
def list(self, request):
# your code
return resp
I am using restframeworks test modules to write test. I need to test a get request for which I created a test as follows
class BlogCommentTest(APISimpleTestCase):
def test_3002_getting_reviewcomment(self):
factory = APIRequestFactory()
request = factory.get(reverse('get-review-comments'), data= {"article": 1})
request.user = self.user
view = ReviewCommentViewSet.as_view({'get': 'list'})
force_authenticate(request, self.user)
response = view(request)
however the way I wrote populates the request.GET with {'article':1} when I want to populate request.DATA. What is the correct way to make the request object whose request.DATA is populated the way I want ?
EDIT
The code for viewset is
class ReviewCommentViewSet(viewsets.ModelViewSet):
"""
viewset to get recursive serialized results
"""
model = models.ReviewComments
serializer_class = serializers.ReviewCommentSerializer
queryset = models.ReviewComments.objects.filter(is_deleted=False)
def serialize_tree(self, queryset):
"""
:return: A helper function to get list of next set of childrens
"""
for obj in queryset:
data = self.get_serializer(obj).data
data['parent'] = self.serialize_tree(obj.children.all().exclude(is_deleted=True))
yield data
def list(self, request):
queryset = self.get_queryset().filter(parent=None, article=request.DATA['article'])
data = self.serialize_tree(queryset)
return Response(data)
def retrieve(self, request, pk=None):
self.object = self.get_object()
data = self.serialize_tree([self.object])
return Response(data)
I am working on Api for my project, i'm using Tastypie 9.9.0. I want the response in Json format for PUT, POST and DELETE operations.
The existing responses like STATUS 201 CREATED, STATUS 204 NO CONTENT, STATUS 410 GONE is fine.
It must respond in a custom format.
for example
1. {
"resource_name": "user",
"action":"password_reset",
"status": "success"
}
2. {
"resource_name": "todo",
"action":"insert",
"status":"sucess",
}
3. {
"resource_name": "todo",
"action":"delete",
"status":"sucess",
}
this is the code i was working on. I dont know how to add custom response messages
class ToDoResource(ModelResource):
user = fields.ToOneField(UserResource, 'user')
class Meta:
queryset = ToDo.objects.all()
fields=['alert_time','description','status','user']
resource_name = 'todo'
filtering = {
'user': ALL_WITH_RELATIONS,
'alert_time': ['exact', 'range', 'gt', 'gte', 'lt', 'lte'],
}
serializer = Serializer()
authentication= MyApiKeyAuthentication()
authorization=Authorization()
always_return_data = True
allowed_methods = ['post','get','put','delete']
def obj_create(self, bundle,request=None, **kwargs):
if not request.user.is_superuser:
try:
bundle.data.pop('user')
except:
pass
return super(ToDoResource, self).obj_create(bundle, request, user=request.user)
def create_response(self, request, data):
"""
Extracts the common "which-format/serialize/return-response" cycle.
Mostly a useful shortcut/hook.
"""
desired_format = self.determine_format(request)
serialized = self.serialize(request, data, desired_format)
return HttpResponse(content=serialized, content_type=build_content_type(desired_format))
def apply_authorization_limits(self, request, object_list):
return object_list.filter(user=request.user)
You can add/modify custom data in get_list(request, **kwargs) and/or get_object(request, **kwargs)
For example,
import json
from django.http import HttpResponse
class ToDoResource(ModelResource):
# ... the rest of code
def get_list(self, request, **kwargs):
resp = super(ToDoResource, self).get_list(request, **kwargs)
data = json.loads(resp.content)
# ... the rest of code
data['meta']['resource_name'] = self._meta.resource_name
data['meta']['action'] = request.method
data['meta']['status'] = ANY_STATUS
# ... the rest of code
data = json.dumps(data)
return HttpResponse(data, mimetype='application/json', status=ANY_STATUS)