aiohttp server - delete file after FileResponse return - aiohttp

I need to delete a temporary created file after it is returned to a request.
The used method looks like:
async def getBackup(self, request):
context = request.rel_url.query['sn']
filePath = createBackup(context)
return web.FileResponse(
path=filePath,
headers={
hdrs.CONTENT_TYPE: 'application/tar+gzip',
hdrs.CONTENT_DISPOSITION: f"attachement;filename=backup.tar.gz;filename*=UTF-8''backup.tar.gz;",
hdrs.CACHE_CONTROL: 'no-cache'
}
)
# os.unlink(filePath) after file has been served ....
I searched for a signal or callback approach but did not find anything in the documentation.
Any hint or suggestions to make it done?

Could you put it inside a context manager or a try/finally? For example:
async def get_backup(self, request):
async with aiofiles.tempfile.TemporaryFile('wb') as fp:
await create_backup(fp)
return web.FileResponse(path=fp.name)
Or the slightly uglier...
async def get_backup(self, request):
file = await create_backup()
try:
return web.FileResponse(path=file)
finally:
await sleep(1) # perhaps not needed
await aiofiles.os.remove(file)

Related

How to upload files with DRF and React?

I'm learning Django Rest Framework, everything was going well until I had to create a service to upload files to my application.As much as I read the documentation, I can't understand it.
First I want to clarify that I am not a programming expert, I am a
newbie but I am here learning more every day.
From what I've managed to understand so far:
Documents and photos are not stored in the database. These files are stored in a folder.
This is correct ?
I have a form where it allows me to upload multiple files
example:
file.txt, document.doc, photo.png etc...
My view (Frontend):
import { useState } from "react";
import axios from "axios";
const Form = () => {
const [state_files, setState_Files] = useState(null);
const UploadFiles = function (event) {
setState_Files(event);
};
const InsertFiles = async function () {
const formData = new FormData();
for (let index = 0; index < state_files.length; index++) {
formData.append("files", state_files[index]);
}
await axios
.post("http://127.0.0.1:8000/api/v1/upload/", formData)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
};
return (
<>
<input
type="file"
name="files"
multiple
onChange={() => InsertFiles(event.target.files)}
/>
<button>Upload All files</button>
</>
);
};
export default Form;
Backend
url.py
path("upload/", Storage_View.as_view(), name="storage-index"),
storage/view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser
class Storage_View(APIView):
parser_classes = [MultiPartParser]
def put(self, request, filename, format=None):
file_obj = request.data['file']
# ...
# What do I have to do here?
# ...
return Response({'received data': request.data})
Questions:
Why don't I see the button to upload files using the DFR tool? see attached files
The documentation does not explain what I have to do inside the function comment
https://www.django-rest-framework.org/api-guide/parsers/
def put(...):
How do I specify the path where you have to store the files you upload?
Please I need guidance.
1: show your models for more detail. you have to use filefield or
imagefield in your model. You can google and read more about these
fields.
2: put is for update, write your post method to save data. You don't
have to really do anything serious there. just check if
serializer.is_Valid() for request.data and if valid do
serializer.save(). the file or image will be uploaded to upload_to
folder which you define in your model and you will get the link.
3: read more about upload_to in Django. you can define this with the
model field.
I used ModelViewSet and this is how the create method looks like -
def create(self, request, format=None):
data = request.data
if isinstance(data, list): # <- is the main logic
serializer = self.get_serializer(data=request.data, many=True)
else:
serializer = self.get_serializer(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)
You are passing a list from frontend and by default, Django works on dictionary, so you will have to manage this. Think of this as your go to code and write your post method.
Feel free to write more if you have doubts, Hope this helps :)

how to get new data at run time from django?

I am working on a Django project with ReactJs frontend. I have to built a simple chat application in that project where users can communicate with each other.
in django views I have following function to read messages
Views.py
class MessagesListAPI(GenericAPIView, ListModelMixin ):
def get_queryset(self):
condition1 = Q(sender=15) & Q(receiver=11)
condition2 = Q(sender=11) & Q(receiver=15)
return Messages.objects.filter(condition1 | condition2)
serializer_class = MessagesSerializer
permission_classes = (AllowAny,)
def get(self, request , *args, **kwargs):
return self.list(request, *args, **kwargs)
this gives me all the messages between user 11 and user 15.
on frontend I am getting these messages from rest Api by calling above function
frontend
const chatApi = axios.create({
baseURL: 'http://localhost:8000/chat/'
})
const getMessages = async() => {
let data = await chatApi.get(`MessageRead/`).then(({data})=>data);
setMessages(data);
}
I am calling this function in an onClick event of button. and displaying the messages by maping messages array.
problem is that at the time when these messages are open to the user. at that time if a new message(data) is added in database. I have to press that button again and call getMessages function again to display that message.
Is there a way to automatically get that new message(record) without calling this function again by pressing a button?

ban command if member is None: [discord.py]

#bot.command()
#commands.has_permissions(ban_members=True)
async def ban (ctx, member:discord.User, reason =None):
if member is None:
await ctx.channel.send("I have no one to ban")
return
if member == ctx.message.author:
await ctx.channel.send("you can't ban yourself")
return
await ctx.guild.ban(member)
await ctx.channel.send(f"{member} was banned")
this is my code
I need to fix:
if member is None:
await ctx.channel.send("I have no one to ban")
return
error :
member is a required argument that is missing.
Put the default value of member as None like this, then it won't be a required arg anymore
async def ban (ctx, member:discord.User = None, reason =None):
add this to your code:
#ban.error
async def ban_error(ctx, error):
if isinstance(error, commands.MemberNotFound):
await ctx.send('I could not find that member...')
This is a error handler
It also prevents member logging :D

Warnings Command

Hello I need help with my warning command. I don't know how to make it say the stuff in chat, if you do show me how to fix this, I would preferably want this in an embed.
#bot.command(pass_context = True)
#has_permissions(manage_roles=True, ban_members=True)
async def warn(ctx,user:discord.User,*reason:str):
if not reason:
await ctx.send("Please provide a reason")
return
reason = ' '.join(reason)
for current_user in report['users']:
if current_user['name'] == user.name:
current_user['reasons'].append(reason)
break
else:
report['users'].append({
'name':user.name,
'reasons': [reason,]
})
with open('reports.json','w+') as f:
json.dump(report,f)
#bot.command(pass_context = True)
async def warnings(ctx,user:discord.User):
for current_user in report['users']:
if user.name == current_user['name']:
await ctx.send(f"```{user.name} has been reported {len(current_user['reasons'])} times : {','.join(current_user['reasons'])}```")
break
else:
await ctx.send(f"```{user.name} has never been reported```")
#warn.error
async def kick_error(error, ctx):
if isinstance(error, MissingPermissions):
text = "Sorry {}, you do not have permissions to do that!".format(ctx.message.author)
await bot.send_message(ctx.message.channel, text)
for and embed put in code. e.g:
embed = discord.Embed(title=f'{member}\'s Warning!',color=0x1d9521)
embed.add_field(name='why he is warned',value=reason, inline=False)
embed.add_field(name="Moderator that warned", value={ctx.author.mention}, inline=False)
i am not sure if this would work but then to send it do
await ctx.send(embed=embed)
another way to send is
await ctx.reply(embed=embed)
to put this out of the embed you could do
await ctx.send("Why they are warned `{reason}`/nThe Responsible Moderator {ctx.author.mention}")
i am not sure if this would work but you can try

DRF APIView returns empty data object when using apisauce but not on browser view

I am trying to query a model to check if an object exists or not using the following APIview function. Unfortunately i am not able to receive any response object in react native apisauce get function as shown below
apisauce function
const checkIfUserExists = (email) =>
client.get("/account/user-exists/?email=" + email);
APIView class
class UserExistsView(APIView):
"""Checks if user exists or not"""
def get(self, request, *args, **kwargs):
username = self.request.GET['email']
try:
user = models.UserProfile.objects.get(email=username)
except models.UserProfile.DoesNotExist:
return Response(data={'message': False})
else:
return Response(data={'message': True})
Results from the browser
What am i doing wrong here?
Print result on shell <Response status_code=200, "text/html; charset=utf-8">
You can do it simplier:
class UserExistsView(APIView):
"""Checks if user exists or not"""
def get(self, request, *args, **kwargs):
email = self.request.GET['email']
user_exists = models.UserProfile.objects.filter(email=email).exists()
return Response(
data={'message': user_exists}
)
If you create a QuerySet and then call .exists(), Django will call the SQL function checking only if the object is in the database, but it will not query it, which is much faster and desired in your call from JS.
Assuming you have a class base component, You could modify your function like below, track the user existence in state. I don't see any errors in your server-side code. but in your javascript code you didn't handle the promise.
checkUserExists= (email) => {
client.get("/account/user-exists/?email=" + email)
.then(response=>{
this.setState({isUserExists : response.data.messgae})
)
}

Resources