Writing a file upload API using Django - python

I have a Django app that revolves around users uploading files, and I'm attempting to make an API. Basically, the idea is that a POST request can be sent (using curl for example) with the file to my app which would accept the data and handle it.
How can I tell Django to listen for and accept files this way? All of Django's file upload docs revolve around handling files uploaded from a form within Django, so I'm unsure of how to get files posted otherwise.
If I can provide any more info, I'd be happy to. Anything to get me started would be much appreciated.

Create a small view which accepts only POST and make sure it does not have CSRF protection:
forms.py
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
views.py
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.http import HttpResponse, HttpResponseServerError
# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file
#csrf_exempt
#require_POST
def upload_file(request):
form = UploadFileForm(request.POST, request.FILES)
if not form.is_valid():
return HttpResponseServerError("Invalid call")
handle_uploaded_file(request.FILES['file'])
return HttpResponse('OK')
See also: Adding REST to Django

Related

Apply django authentication for all views

I am trying to implement Django basic authentication for all of the views in my views.py file. Although I can add the authentication code snippet in every view, but it will not be easy to apply this to upcoming views. Is there any way that every view in my views.py will automatically check for the authentication?
views.py
def mgmt_home(request):
##############################################################
# This code is repetitive
##############################################################
if request.user.is_anonymous:
return redirect("/login")
##############################################################
test_name = Test.objects.all()[0].test_name
metadata = {
"test_name": test_name,
}
return render(request, "mgmt_home.html", metadata)
Is there any way where I can avoid this repetitive code in all of my views?
you can use 'login_required()' decorator or 'LoginRequiredMixin' class from django authentication.
https://docs.djangoproject.com/en/3.1/topics/auth/default/
How to specify the login_required redirect url in django?
You have 2 options:
from django.contrib.auth.decorators import login_required
You can add this #login_required() decorator to your every view and it will automatically redirect a user to the login page (or whatever page you want to send the user to) any time your user is not logged in.
This option, in your case, I would not recommend, as this might be an overkill and not required for your simple problem. The solution is to create a custom Middleware and add your code to it, and then, of course, add the Middleware to the Settings.py file. This way, each time your views run, your Middlewares will run prior to that. In fact, that's the purpose of Middlewares. They are designed to reduce redundancies and problems exactly such as yours.
Create a middleware.py file anywhere on your python path. Add the below codes to your created middleware.py file
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
def redirect_to_login():
return HttpResponseRedirect(reverse_lazy('users:login'))
class AuthPageProtectionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
if request.user.is_authenticated:
if not request.user.is_admin:
return redirect_to_login()
else:
return redirect_to_login()
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
NOTE
You can replace the redirection URL with your application-specific one.

Where to best execute database operations using Django framework?

Thanks in advance for any help. I am new to django specifically as well as web development in general. I have been trying to teach myself and develop a website using the Django framework and while everything is working so far, I am not sure if I am really doing things in the best possible way.
Typically, within my django app, I will have certain points where I want to modify the contents of my database model in some way. A typical use case is where I have button on my site that says "Add a post":
models.py:
from django.db import models
# data model import
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
post = models.CharField(max_length=1024)
urls.py:
from django.urls import include, path
from . import views
urlpatterns = [
path('', views.post, name='new_post'),
path('post_exec', views.post_exec, name='post_exec'),
]
views.py:
from django.contrib import messages
from django.shortcuts import render, redirect
# import data models
from django.contrib.auth.models import User
from .models import Post
def post(request):
# make sure the user has privileges
user = User.objects.get(id = request.user.id)
if not user.is_superuser:
return redirect('home')
return render(request, 'post.html')
def post_exec(request):
# make sure the user has priveledges
user = User.objects.get(id = request.user.id)
if not user.is_superuser:
return redirect('home')
# create the post
new_post = Post.objects.create()
new_post.user = user
new_post.post = request.POST['post']
new_post.save()
# this could redirect to a confirmation page or something too
return redirect('home')
You can see what I am doing here is that everytime I need a change to the database due to user input, I am executing the code to do the requested database change in a django view and then redirecting to another page following completion of the database change. While this works, it feels kind of clunky (you end up needing pages that you never actually use), it seems pretty sketchy in terms of security (although I am checking for credentials on each page), and I imagine there is a better way to do this.
Can any experience Django developers offer some advice for how I should be best structuring my project for these specific types of common database operations?
The Django's views is a good place to organize the project's CRUD system so users can manage their data. You can use the class-based views to group the GET, POST etc requests. Also there are better ways of using the authorization system with the login_required() decorator, the LoginRequiredMixin class and other solutions that you can rich here

Send the response to user from other file instead of views.py form DRF

I am working on DRF in which I have created multiple pythons and importing that file into views.py but when I am trying to send the response to the user from another file it is not working I understand the behind the reason but is there any way to send the response to the user from other than view.py.
view.py Structure
#restframework view and all
from concurrent.futures import ThreadPoolExecutor
import other as o
call FileView(APIView):
#parseclass
def post(self,request):
o.func(d)
Other.py
from rest_framework.response import Response
from rest_framework.status import status
from django.conf import setting
def func(d):
return Response({"A":"OK"})
but Response is not coming to the user end.
is there any way to send a response from other.py to the user instead of getting value and then send the response from the view.py?
I am also implementing multithreading in my DRF.
Just add return and it should work:
class FileView(APIView):
#parseclass
def post(self,request):
return o.func(d)
If you want to skip this step and call view in others.py directly. Just make that an APIView and register it in urls.py. It should work

django project multiple user use the same project

I am new to django and web programming. Right now, I have created a django project for configuration form generation. It allows the user to input the values and generate a configuration form once the user got the URL.
Project name: portal, App name: home, input_data.txt: a text file stored the values for the corresponding parameter and it will be read for further processing
It works fine for myself, but multiple users use it at the same time. It doesn't work. what can I do in order to allow multiple users use it at the same time?
forms.py
from django import forms
from .models import FormGen
from .models import BB_Data
class FinalForm(forms.ModelForm):
class Meta:
model=FormGen
field=['full_name','backbone_number']
class BBForm(forms.ModelForm):
class Meta:
model=BB_Data
fields=['backbone_name','IP','numbers']
widget={'numbers':forms.TextInput(attrs={'readonly':'readonly'})}
views.py
from django.shortcuts import render,HttpResponse,redirect
from .forms import FinalForm,BBForm
from django.core.files import File
import re
def replacePara(template,para):
for key,val in para.items():
template=template.replace(key,val)
return template
def create(request):
title="Router Generator"
form=FinalForm(request.POST or None)
context={
"template_title":title,
"form":form,
}
if(form.is_valid()):
form_data={
"HNAME":form.cleaned_data.get("Hostname"),
"ROLE":form.cleaned_data.get("Router_Role"),
}
form.save()
f=open('./input_para.txt','r')
a=f.read();
f.close();
tt=replacePara(a,form_data)
b=open('./input_data.txt','w')
b.write(tt)
b.close()
return redirect('/backbone')
return render(request,"home/form.html",context)
def bb(request):
title="Backbone Information"
if request.method=="POST":
form=BBForm(request.POST)
if form.is_valid():
bb_form={
'BBNAME':form.cleaned_data.get('backbone_name'),
'BBIP':form.cleaned_data.get('IP'),
}
a=int(form.cleaned_data.get('numbers')
datainput=''
if a==1:
f=open('./bb_set.txt','w')
f.write(bb_form)
f.close()
else:
f=open('./bb_set.txt','a')
outBB.write(bb_form)
outBB.close()
form.save()
f=open('./input_data.txt','r')
t=f.read()
tt=int(t.split()[7]) #it get the max number of backbones
if(at<tt):
at=at+1;
bb=BBForm(initial={'numbers':str(at)})
context={
"template_title":title,
"form":bb
}
return render(request,"home/bb.html",context)
else:
# generate the configurate text file #
content=final # content store the configurations
filename="ConfigForm.txt"
response=HttpResponse(content,content_type='text/plain')
response['Content-Disposition']='attachment; filename={0}'.format(filename)
return response
else:
return HttpResponse("something wrong")
else:
form=BBForm(initial={'numbers':"1"})
f=open('./input_data.txt','r')
t=f.read()
tt=int(t.split()[7])
context={
'template_title':title,
'form':form,
'max':tt
}
return render(request,"home/bb.html",context)
input_para: it is the text file stored the name of the parameter
input_data: it is the text file stored the values for correspond parameter
bb_set: it is the text file stored all the backbone information
You're saving data to a single file, with no regards as to users. If I go to your website, I'll be writing to the same input_data.txt, input_para.txt, and bb_set.txt files as anyone else also visiting.
This is not the way to persist user data for a website/service. You should be using a database.
Luckily, you're using Django, which has phenomenal database integration, and it's actually really easy. The hardest part, for you, will be designing the database. You'll want a User model, against which you can record input_data, input_para, and bb_set data against, from what I can tell.
I recommend you follow the Django tutorial, specifically this section, and perhaps also read up on database design, (including normalisation of data, which is more interesting than it sounds).

How to create Django restful URL Patterns?

I am trying to create a restful api using class based views in django.
class SomeAPI(MultiDetailView):
def get(self,request,format=None):
#some logic
def post(self,request,format=None):
#some logic
I want to process a get request like www.pathtowebsite.com/api?var1=<someval>&var2=<someval>&var3=<someval>
My post url would be www.pathtowebsite.com/api/unique_token=<token_id>
Basically a get request would generate a unique token based on some parameters and a post request would post using that token.
How would my URL file look like in such a scenario?
P.S I have hardly ever worked with class based views.
First of all: DRF will do a lot of your legwork for you, even generate consistent URLs across your API. If you want to learn how to do things like this in the Django URL dispatcher then you can embed regexes in your URLS:
project/urls.py:
from django.conf.urls import url
from project.app.views import SprocketView
urlpatterns = [
url(r'^api/obj_name/(P<id>[a-f0-9]{24})/$', SprocketView.as_view()),
url(r'^api/obj_name/unique_token=(P<id>[a-f0-9]{24})/$', SprocketView.as_view()),
]
project/app/views.py
from django.shortcuts import get_object_or_404
from django.views.generic import View
from .forms import SprocketForm
from .models import Sprocket
class SprocketView(View):
def get(request, id):
object = get_object_or_404(Sprocket, pk=id)
return render(request, "sprocket.html", {'object':object}
def post(request, id):
object = Sprocket.get_or_create(pk=id)
object = SprocketForm(request.POST, initial=object).save(commit=False)
object.user = request.user
object.save()
return render(request, "sprocket.html", {'object':object, 'saved':True})
That's a lof of functionality that frameworks are supposed to lift from you and I suggest reading about Django CBV. One resource I can wholeheartedly recommend is Two Scoops.

Categories