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).
Related
I'm developing an application that requires users to upload a massive directory of multiple files/file types/subfolders. It will be handling 10's possibly 100s of GB per user, so having a progress bar displayed while uploading will be very helpful in informing the user the progress of the massive files.
My current setup is based on the following answer to another question: https://stackoverflow.com/a/52016594/15739035
Here is a simplified setup:
models.py:
class Feed(models.Model):
user=models.ForeignKey(User, on_delete=models.CASCADE)
text=models.TextField(blank=False, max_length=500)
class FeedFile(models.Model):
file = models.FileField(upload_to="files/%Y/%m/%d")
feed = models.ForeignKey(Feed, on_delete=models.CASCADE)
forms.py:
class FeedModelForm(forms.ModelForm):
class Meta:
model = Feed
fields = ['text']
class FileModelForm(forms.ModelForm):
class Meta:
model = FeedFile
fields = ['file']
widgets = {
'file': ClearableFileInput(attrs={'multiple': True}),
}
# widget is important to upload multiple files
views.py:
def upload_files_view(request):
user = request.user
if request.method == 'POST':
form = FeedModelForm(request.POST)
file_form = FileModelForm(request.POST, request.FILES)
files = request.FILES.getlist('file') # field name in model
if form.is_valid() and file_form.is_valid():
feed_instance = form.save(commit=False)
feed_instance.user = user
feed_instance.save()
total_files = len(files) # Get the number of files in 'files'
files_count = 0 # Use to show user the progress out of 'total_files'
for f in files:
file_instance = FeedFile(file=f, user=use, feed=feed_instance)
file_instance.save()
progress = f"{total_files}/{files_count}"
# render(request, 'some_folder/upload_progress.html', {'file_form': file_form, 'form': form, 'progress': progress}) # somehow refresh the page showing 'progress' in an html tag?
files_count += 1
return redirect('upload_success_page')
else:
form = FeedModelForm()
file_form = FileModelForm()
return render(request, 'some_folder/file_upload.html', {'file_form': file_form, 'form': form})
My end goal is to get the total file count (like the above views.py file shows), detect what file is currently being uploaded, and return that value to a template for the user to monitor somehow. (You can see what I've attempted above in the views.py file, however this method doesn't work for a number of reasons.)
My question:
How do I get this information while the files are being uploaded, and send it to the template/page the user is viewing?
Here is an example of the Google Drive folder upload progress bar, a folder of 1185 files is being uploaded and the current progress is 11:
In terms of research I've done, I've found many similar questions about using Ajax. All of the other StackExchagne questions are either really old or don't have an answer and weren't much help. This article seemed promising, however it appears that the code is unfinished, and I couldn't get it to work: https://anshu-dev.medium.com/file-upload-progress-bar-using-django-and-ajax-ba4eb7482d9c
In my opinion the ideal method would be entirely using Django views.py, however I'm not entirely sure if or how this would be possible.
I really appreciate any help I can get, thank you for your time!
I'm trying to write a simple IF statement on checking if a lastname in a database exists before a user hits the submit button to create a new record. Here is my code so far, I'm new to Django and Python so the help is appreciated.
I made a variable called lastname, the thought process here is when the user hits submit, it checks the database first before the commit to warn them with a popup if the lastname exists to prevent duplicate records. It would actually be really cool to have it when a person exits the field for it to run the script before they finish filling out the form to save time.
#views.py
from .models import StudentCheck
from django.shortcuts import render
from django.http import HttpResponse, Http404, HttpResponseRedirect
from forms.forms import NewStudentForm
def NewStudentFormCheckList (request):
if request.method == 'POST':
form = NewStudentForm(request.POST)
lastname = StudentCheck.lastname
if form.is_valid():
newstudent= form.save()
else:
form = NewStudentForm()
return render(request, 'forms/newstudentcheck_form.html', {'form': form})
Here is my test code to see if query is working correctly and i keep getting a error that the query set doesnt exists.
from .models import StudentCheck
from django.core.exceptions import ValidationError
from django.shortcuts import render
from django.http import HttpResponse, Http404, HttpResponseRedirect
from forms.forms import NewStudentForm
def NewStudentFormCheckList (request):
if request.method == 'POST':
form = NewStudentForm(request.POST)
lastname = StudentCheck.lastname
number_lastnames = StudentCheck.objects.get(lastname__exact=lastname)
if form.is_valid():
newstudent= form.save()
print (number_lastnames)
else:
form = NewStudentForm()
return render(request, 'forms/newstudentcheck_form.html', {'form': form})
You can get all the entries in the database which have a given value already set using the field lookup exact (see here for more informations).
In your case it'll be StudentCheck.objects.get(lastname__exact=yourvalue). This would give you a QuerySet, and if you want to know how many entries have the given last name, you have to use count() on this QuerySet to know how many entries it has.
You can use this solutions in two different places:
Directly in the view, when receiving the POST values.
In a custom validator, which would be used in the definition of the model (see here to know how to do)
I would recommend to use the second one, as it would be easier to provide custom information for the user on why it's data where not accepted.
Both of these methods requires the data to be passed to the server to be validated though. Otherwise you can define a view that would receive the lastname and return if it's present already in the database in some way (JSON for example), which would be called using Ajax when the user click on the submit button.
Edit:
As per request of OP, here's an example of the custom validator:
from django.core.exceptions import ValidationError
from .models import StudentCheck
def validate_lastname(value):
number_lastnames = StudentCheck.objects.get(lastname__exact=value)
if number_lastnames > 0:
raise ValidationError(
'%s already exists' % value,
)
Now you can use this custom validator with attribute validators, either in the definition of your model or inside the definition of your form like this: lastname = models.CharField(validators=[validate_lastname]).
Hope it helps!
I created a form in my Django project, i would now like to have this form interact with a database.
Basically, when the user inputs some data, it must be sent to a database. Note: i already have a database in my django project, i defined it on my settings.py, but i must not send the data to that DB, but to a different database, since that db will interact with another Python script.
Now, what i don't know, is how can i use another database in Django? Where should i define the whole second database configuration?
This is what my basic view looks like at the moment:
def input(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = InputForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
messages.success(request, f"Success")
# if a GET (or any other method) we'll create a blank form
else:
form = InputForm()
return render(request,
"main/data.html",
context={"form":form})
You need to define the second database in settings, see:
https://docs.djangoproject.com/fr/2.2/topics/db/multi-db/
Then you will just save the form in a particular database like this:
form.save(using='database_name')
Or if you're using it for a particular model in your project you can overload save method of this model to be stored in another DB:
class SomeModel(models.Model):
foo = models.CharField(max_length=100)
def save(self, ...): # ALL the signature
super(SomeModel, self).save(using='database_name')
I have written a simple feedback application in django. It's not particulairly complex, basically it allows authenticated users to write a shot message with a subject line and submit that message via a form. I then allows who are in a selected group to view user submitted feedback. In the future I may add more functionality but for now it does what I want.
Here comes my question, the site I'm building has multiple places where I would like to use the feedback app, for example I have a "what do you think of the site?" kind of page at /dev/feedback/ I also have one for customer support feedback at "/support/feedback/" Currently I have just copied the code from my mysite.apps.dev.feedback over to mysite.apps.support.feedback.
The problem is that this has now created two separate copies of the same code. Despite having just written the app the two versions are already starting to diverge which is annoying. My question is simply how do I create multiple instances of the same app in a django site with distinct database models?
Some resources I've found related but not helpful are https://docs.djangoproject.com/en/dev/topics/http/urls/ and Reversing namespaced URLs in Django: multiple instances of the same app The first page does not offer much on the issue and the second page provides somewhat cludgey and impractical solutions that seem to be both unrelated and more work than their worth. Is there a proper way to implement multiple instances of the same django app?
Single model approach
I'd personally try to keep this as one app and have a view that can handle being posted from multiple locations / tag them appropriately.
As S.Lott says, this is the way to go. I am providing alternatives if you're curious about methods to keep your code in one place in other situations.
For example, you could add a category field to your model, set up a single url conf which accepts an argument in the URL such as /(?P<category>\w+/feedback/$ and have the view simply tag the feedback with the appropriate category.
class MyForm(forms.ModelForm):
class Meta:
model = Feedback
def my_view(request, category):
form = MyForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
feedback = form.save(commit=False)
feedback.category = category
feedback.save()
return http.HttpResponse("Thanks for posting!")
return render(request, "mytemplate.html", {'form': form})
# urls.py
(r'^(?P<category>\w+)/feedback/$', 'my_view')
# user can visit dev/feedback or support/feedback and the feedback will be tagged appropriately
Abstract base class
Another solution is to build an abstract base class, then create subclasses for your distinct tables. That should solve the issue with your code getting out of sync.
You'd have a single abstract model (which has no tables) from which your "real" models in your separate apps would be based on.
Dynamically generated views
If you must have separate models, you could potentially write a dynamically constructed view.
def view_generator(model_class):
class MyForm(forms.ModelForm):
class Meta:
model = model_class
def my_view(request):
form = MyForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return http.HttpResponse("Thanks for posting!")
return render(request, "mytemplate.html", {'form': form})
return my_view
# urls.py
from foo import view_generator
(r'^my_first_feedback_form', view_generator(Model1))
(r'^my_second_feedback_form', view_generator(Model2l))
how do I create multiple instances of the same app in a django site with distinct database models?
You shouldn't.
You simply use the feedback app model in the other two apps with a simple from feedback.models import Feedback.
Then your support app can create, retrieve, update and delete Feedback objects.
Your dev app, similarly, can create, retrieve, update and delete Feedback objects because it imported the model.
That's all that's required: import.
Thanks Yuji Tomita for a very thorough answer, my final solution is derived very closely from his suggestion, but is different enough that I thought I would post it as another option if someone else runs into the same situation that I am in.
Firstly in my mysite.apps.feedback.models file I put
class Feedback( models.Model ):
subject = models.TextField( max_length=100 )
body = models.TextField( max_length=100 )
# Some other stuff here...
# Finally I used the suggestion above and created a field which I
# use to label each entry as belonging to a specific instance of the app.
instance_name = models.TextField( max_length=20 )
In my mysite.apps.feedback.views file I put
def save_message( request, instance_name ):
if request.method == 'POST':
form = FeedbackFrom( request.POST )
if form.is_valid():
form.instance.instance_name = instance_name
form.save()
return render("feedback/thanks.html")
else:
return render("feedback/submit.html", {'form':form })
else:
return render("feedback/submit.html",{'form':FeedbackForm()})
#user_passes_test( is_staff )
def all_messages( request, instance_name ):
messages = Feedback.objects.filter( instance_name = instance_name )
return render("feedback/view_all.html",{'feedback':messages} )
In my mysite.apps.dev.urls file I put
url(r'^feedback/', include('mysite.apps.feedback.urls'),
{'instance_name':'dev'}),
In my mysite.apps.support.urls file I put
url(r'^feedback/', include('mysite.apps.feedback.urls'),
{'instance_name':'support'}),
This will separate feedback messages by app instance. Note that my actual code is more complex but this should be good enough for anyone with a similar problem to get a solution up and running pretty quickly. Hope this is useful to anyone in a similar situation. Thanks again to Yuji Tomita for the suggestions upon which this solution is based.
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