Undefined variable error during splitting views.py into modules - Django - python

My codes in views.py becomes larger day by day, and now I want to split it into modules. But I have trouble with variables. Problem is in that I don't where should I declare variables, or import built-in modules: in my custom module, or views.py. Here is my codes:
views.py:
#login_required(login_url='sign_in')
def result(request):
find_by_fives()
context = {
'last_uploaded': last_uploaded,
'words_count': words_count,
'characters_count': characters_count
}
return render(request, 'result.html', context)
find_by_fives.py(is my custom module):
import glob
from .models import OriginalDocument
from django.shortcuts import render
def find_by_fives():
last_uploaded = OriginalDocument.objects.latest('id')
original = open(str(last_uploaded.document), 'r')
original_words = original.read().lower().split()
words_count = len(original_words)
open_original = open(str(last_uploaded.document), "r")
read_original = open_original.read()
characters_count = len(read_original)
path = 'static/other_documents/doc*.txt'
files = glob.glob(path)
Error: NameError: name 'last_uploaded' is not defined
Note: This is not my entire view, all I want to know is just where should I declare context, variables, and imports.

Ok, I see - "find_by_fives.py" is a function, right? So the variables that you declare inside it lives only there. So when you call this function from the views.py - they get declared and then, when the function is over they get deleted. If you want to use them in the views.py - you should return them and assign a variable there, then pass them to the context:
#login_required(login_url='sign_in')
def result(request):
last_uploaded, words_count, characters_count = find_by_fives()
context = {
'last_uploaded': last_uploaded,
'words_count': words_count,
'characters_count': characters_count
}
return render(request, 'result.html', context)
def find_by_fives():
last_uploaded = OriginalDocument.objects.latest('id')
original = open(str(last_uploaded.document), 'r')
original_words = original.read().lower().split()
words_count = len(original_words)
open_original = open(str(last_uploaded.document), "r")
read_original = open_original.read()
characters_count = len(read_original)
path = 'static/other_documents/doc*.txt'
files = glob.glob(path)
return last_uploaded, words_count, characters_count

Related

How to call class method in Django URLs path?

How to call class method in Django URLs path?
I want to call data_display method inside DataLoad class. how can i call it in my URLs.py file? so when i hit the path then it will render to the data_display.html template.
views.py
class DataLoad:
def __init__(self, save_path, name_of_file):
self.save_path = save_path
self.name_of_file = name_of_file
def file_load(self):
file_path = os.path.join(self.save_path, self.name_of_file+".html")
return file_path
def data_display(request,*args, **kwargs):
df = pd.read_csv("/home/satyajit/Desktop/opensource/data/us_amz.csv", low_memory=False)
json_records = df.reset_index().to_json(orient ='records')
data = []
data = json.loads(json_records)
context = {'data': data}
return render(request, "home/data_display.html", context)
urls.py
from apps.home.views import DataLoad
data = DataLoad.data_display(request)
urlpatterns = [
#path('data_display', DataLoad.as_view(), name='data_display'),
path('data_display', data, name='data_display'),
]
According to the documentation, your view must extends the View class and your method should be name as the HTTP method you want to match.
from django.views import View
class DataLoad(View):
def get(request, **kwargs):
df = pd.read_csv("/home/satyajit/Desktop/opensource/data/us_amz.csv", low_memory=False)
# ...
return render(request, "home/data_display.html", context)
# url.py
from apps.home.views import DataLoad
urlpatterns = [
path('data_display', DataLoad.as_view(), name='data_display'),
]
Dependency injection
This part answer the OP comment.
If you want to have a better decoupling of you DataLoad from the request, you will need to split your view from your Dataload classes.
This is called dependency injection.
So you have your DataLoad classes that don't use any HTTP related things:
# file: core/dataload.py
class DataLoad:
def __init__(self, save_path, name_of_file):
self.save_path = save_path
self.name_of_file = name_of_file
def file_load(self):
file_path = os.path.join(self.save_path, self.name_of_file+".html")
return file_path
def data_display():
df = pd.read_csv("...us_amz.csv", low_memory=False)
json_records = df.reset_index().to_json(orient ='records')
return json.loads(json_records)
You then build a view that will use this class.
Your View depends on DataLoad.
You inject a DataLoad instance into your view.
Your DataLoad class is decoupled from your view.
# file: views.py
class DisplayDataView(View):
data_load_service = None
def __init__(self, data_load_service):
self.data_load_service = data_load_service
def get(self, request):
return render(request, 'home/data_display.html', {
'data': this.data_load_service.data_display(),
}
You then build your url passing a DataLoad instance to your view
# file: urls.py
from core.dataload import DataLoad
data_load_service = DataLoad(...)
urls = [
path(
'data-load',
DisplayDataView.as_view(
data_load_service=data_load_service,
),
name='data-load',
),
]
This is the basic idea. I would personaly find another place for the DataLoad instanciation but it should do the trick for you until you find out a better way to organize all this.
Main point here is decoupling what your business logic is from the HTTP part (ie: request/response) of your application.

How to fix UnboundLocalError in Django website

I am getting this error, "local variable 'stu_details' referenced before assignment". How can i fix it please.
views.py
def assignment_page(request):
if request.method == "POST":
get_course_name = request.POST.get('get_course_name')
add_courses_get = add_courses.objects.get(Course_Name=get_course_name)
stu_course_all_stu = add_courses.objects.filter(Course_Name=add_courses_get)
for all_stu_details in stu_course_all_stu:
for stu_details in all_stu_details.student.all():
id_ = stu_details.student_ID
name = stu_details.student_name
context3 = {"stu_details":stu_details, "id_":id_, "name": name, 'stu_course_all_stu':stu_course_all_stu}
return render(request, 'assignment_page.html', context3)
else:
return redirect('/')
It's look like your variable context3 should be array with information about every students. You declare context3 after loop, but stu_details and other variables exist in the loop.
I understand that you need something like this.
context3 = []
for all_stu_details in stu_course_all_stu:
for stu_details in all_stu_details.student.all():
id_ = stu_details.student_ID
name = stu_details.student_name
context3.append({"stu_details":stu_details, "id_":id_, "name": name, 'stu_course_all_stu':stu_course_all_stu})
context = {'context3': context3}
return render(request, 'assignment_page.html', context)
I hope I understand your problem right.

Name Error in Django - Nested Function in Views Function - Saving to Database

Using Django, While trying to save the answers from the User to the Database, it is showing me a Name Error. I have nested a function inside a views function, it works correctly when i do not attempt to save the data to the database. But once i try to put in code inside the views function to save the data, it produces this name error. Below are the files with the code,
models.py file
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class ansquestions(models.Model):
m_invested = models.CharField(max_length=100)
p_return = models.CharField(max_length=100)
years = models.CharField(max_length=100)
inflation_yes_no = models.CharField(max_length=100)
r_output = models.TextField(default=True)
date_answered = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
forms.py file
from django import forms
from .models import ansquestions
class ansquestionsForm(forms.ModelForm):
class Meta:
model = ansquestions
fields = ['m_invested', 'p_return', 'years', 'inflation_yes_no', 'r_output', 'date_answered', 'author'
]
views.py file (Note : the fvinvestment function is nested under investmentfvcalc function. when pasting in here, its not showing as indented under the investmentfvcalc, but in my real code the fvinvestment function is indented and nested under the investmetncalc function. )
from django.shortcuts import render
#from django.http import HttpResponse
from .models import ansquestions
from .forms import ansquestionsForm
def investmentfv(request):
idata = { 'tmi':tmi, 'pry':pry, 'ys':ys, 'qinf':qinf }
return render(request, 'fvalueapp/investmentfv.html', idata)
def investmentfvcalc(request):
if request.method == 'POST':
form = ansquestionsForm(request.POST)
if form.is_valid():
total_i = request.POST.get["m_invested", '']
perc_r = request.POST.get["p_return", '']
years_i = request.POST.get["years", '']
makeup_infl = request.POST.get["inflation_yes_no", '']
ansquestions_obj = ansquestions(m_invested=total_i, p_return=perc_r, years=years_i, inflation_yes_no=makeup_infl)
ansquestions_obj.save()
def fvinvestment():
global fv_i_value
global r_output
#global makeup_infl ( global variable might be needed for technique for above. as error says makeup_inf is not defined )
if makeup_infl=='no':
i_return = (float(perc_r))
elif makeup_infl=='yes' and int(years_i)<=5:
i_return = (2+float(perc_r))
elif makeup_infl=='yes' and int(years_i)>5 and int(years_i)<=9.99 :
i_return = (4 + float(perc_r))
elif makeup_infl=='yes' and int(years_i)>= 10 :
i_return = ( 6 + float(perc_r))
fv_i_value = int(total_i) * (1 + (i_return)*.01) ** int(years_i)
r_output = 'Your money would grow to the total of ' + str(fv_i_value) +' dollars at the end of this timeframe.'
fvinvestment()
idata = { 'tmi':tmi, 'pry':pry, 'ys':ys, 'qinf':qinf, 'r_output': r_output }
return render (request, 'fvalueapp/fvinvestmentcalcresults.html', idata)
Errors :
Running the above code it gives me the error "NameError at investmentfv/Investementfvcalc" "free variable 'makeup_infl' referenced before assignment in enclosing scope " i than later would put the variable "makeup_infl" as a Global variable in the fvinvestment function, it than would produce error "NameError - name 'makeup_infl' is not define
Change fvinvestment to global scope, pass in these variables: years_i and makeup_infl
def fvinvestment(years_i, makeup_infl):
....
This will also solve your makeup_infl not defined error

expected str, bytes or os.PathLike object, not InMemoryUploadedFile

I have a method to read a Newick file and return a String in Django framework which is the following:
def handle_uploaded_file(f):
output = " "
for chunk in f.chunks():
output += chunk.decode('ascii')
return output.replace("\n", "").replace("\r", "")
def post(self, request):
form = HomeForm(request.POST, request.FILES)
if form.is_valid():
input = handle_uploaded_file(request.FILES['file'])
treeGelezen = Tree(input, format=1)
script, div = mainmain(treeGelezen)
form = HomeForm()
args = {'form': form, 'script': script, 'div': div}
return render(request, self.template_name, args)
Which works fine for normal Newick files but i also have some files which have a string at the beginning of the file. I'm trying to make another method which checks if the file has the following String before it (which is the case in some files): "newick;" and removes the string if found. It works locally but i can't seem to merge them. This is how it locally looks like:
def removeNewick(tree_with_newick):
for x in tree_with_newick:
if x.startswith('newick;'):
print('')
return x
filepath = "C:\\Users\\msi00\\Desktop\\ncbi-taxanomy.tre"
tree_with_newick = open(filepath)
tree = Tree(newick=removeNewick(tree_with_newick), format=1)
which works perfectly when i specify the path just in python so i tried combining them in Django like this:
def handle_uploaded_file(f):
tree_with_newick = open(f)
for x in tree_with_newick:
if x.startswith('newick;'):
print('')
return cutFile(x)
def cutFile(f):
output = " "
for chunk in f.chunks():
output += chunk.decode('ascii')
return output.replace("\n", "").replace("\r", "")
def post(self, request):
form = HomeForm(request.POST, request.FILES)
if form.is_valid():
input = handle_uploaded_file(request.FILES['file'])
treeGelezen = Tree(input, format=1)
script, div = mainmain(treeGelezen)
form = HomeForm()
args = {'form': form, 'script': script, 'div': div}
return render(request, self.template_name, args)
Which doesn't work and it gives the following error:
expected str, bytes or os.PathLike object, not InMemoryUploadedFile
I've been working on it for two days already and couldn't figure out why the error is popping up.
The error is happening because the function handle_uploaded_file(f) is trying to open an already opened file.
The value of request.FILES['file'] is a InMemoryUploadedFile and can be used like a normal file. You don't need to open it again.
To fix, just remove the line that tries to open the file:
def handle_uploaded_file(f):
for x in f:
if x.startswith('newick;'):
print('')
return cutFile(x)
In my setting.py I had
MEDIA_ROOT = os.path.join(BASE_DIR, 'media'),
when it should've been
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
which solved this error for me.
the solution for me;
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
instead of :
MEDIA_ROOT = [os.path.join(BASE_DIR, 'media')]
in settigs.py

How to insert data to django database without forms

Hi I am trying to insert data to the database in django without forms.
This is my views.py file
def updatetrans(request):
json_data=open('/home/ttt/Abc/a.json').read()
data = json.loads(json_data)
for pk, pv in data.iteritems():
for k,v in pv.iteritems():
try:
print k, " =>> ", pv['transcript'][1]
except:
pass
This is my url.py file
url(r'^updatetrans/$', 'booki.account.views.updatetrans', name='updatetrans'),
Here is my models.py file. I have created two tables. And want to insert data in both of them separately.
class TransType(models.Model):
name = models.TextField()
def __unicode__(self):
return self.name
class Trans(models.Model):
trans = models.ForeignKey(TransType)
script = models.CharField(max_length=200)
def __unicode__(self):
return self.trans
I am getting the output on console. That output I want to save to the database.
Plz help.
Thank you.. I tried some other way. I am getting error as:
global name 'TransType' is not defined
Not inserted ==> e
My code:
def updatetrans(request):
json_data=open('/home/ttt/Ali/a.json').read()
data = json.loads(json_data)
for pk, pv in data.iteritems():
for k,v in pv.iteritems():
try:
trans_type = TransType.objects.get_or_create(name=k)
trans = Trans()
trans.trans_id = trans_type.id
trans.script = pv[k][1]
trans.save()
print " Inserted ==>", pv[k][1]
except Exception, e:
print e
print "Not inserted ==>", pv[k][1]
pass
return HttpResponse("Done")
The problem is solved. The answer is as follows.
To Store the records in the django database without using any input or form.
To avoid duplicate entries in the database.
This is my views.py file
def updatetrans(request):
json_data=open('/home/ttt/Ali/a.json').read()
data = json.loads(json_data)
for pk, pv in data.iteritems():
for k,v in pv.iteritems():
try:
trans_type = TransType.objects.get_or_create(name=k)
trans = Trans()
trans.transtype_id = trans_type[0].id
if isinstance(pv[k], basestring):
script = pv[k]
else:
print "****** List ****"
script = pv[k][1]
trans.script = script
trans.save()
print " Inserted ==>", script
except Exception, e:
print e
#print "Not inserted ==>", pv[k][1]
pass
return HttpResponse("Done")
This is my models.py file.
class TransType(models.Model):
name = models.TextField()
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.name
class Trans(models.Model):
transtype = models.ForeignKey(TransType)
script = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
class Meta:
unique_together = (("transtype", "script"),)
def __unicode__(self):
return self.trans
You just want to save data to database, so you can do it like this easily
>> cd project_directory
>> python manage.py shell
>> from xxx.models import TransType,Trans
>> tt = TransType.objects.create(name='read from file')
>> Trans.objects.create(trans=tt, script='read from file')
or write a python script to import data to database, put it in your project directory,run python manage.py shell then import yourscript
if you don't like python manage.py shell, just set DJANGO_SETTINGS_MODULE environment, then just run python yourscript in terminal. Such as
import os
os.environ["DJANGO_SETTINGS_MODULE"] = "yoursite.settings"
# The above two lines could be written simply as:
# from project.wsgi import *
from xxx.models import import TransType,Trans
TransType.objects.create()
Trans.objects.create()
remember to replace xxx with your app name
see QuerySet API:https://docs.djangoproject.com/en/dev/ref/models/querysets/#create
Chinese people could see here (other people could just read the code): http://www.ziqiangxuetang.com/django/django-import-data.html
You can do it using Model.objects.create()
Let's say you're receiving data from post form and want to save in QuillModel, here's how to do it in python2 django
from __future__ import unicode_literals
from django.http import HttpResponse
from django.shortcuts import redirect, render
from .forms import TemplateForm
from .models import QuillModel
def app3(request):
if request.method == "POST":
print(request.POST)
html_content = request.POST.get('html_content')
input_area = request.POST.get('input_area')
if html_content and input_area:
obj = QuillModel.objects.create(html_content=html_content, input_area=input_area)
obj.save()
return redirect('/app3/app3')
else:
form = TemplateForm()
return render(request, 'app3/forms/f1_post_form.html', {'form' : form})
See the if request.method == "POST": part for saving into database.
Since I have been doing the same thing..
For example:
models.py
class Dataset(models.Model):
hash = models.CharField(max_length=32)
category = models.CharField(max_length=10)
views.py
if request.method == "POST":
uploaded_file = request.FILES['document']
fs = FileSystemStorage()
fs.save(uploaded_file.name,uploaded_file)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
media_path = os.path.join(BASE_DIR,'dataset')
full_path=os.path.join(media_path,uploaded_file.name)
f = default_storage.open(full_path, 'r')
data = f.read()
for i in data.split("\n"):
hash,category = i.strip("\n").split(",")
Dataset.objects.create(hash=hash,category=category)
print("yes")
f.close()
Conclusion
You just specify your models and then create with what variable or column that you have.
MODELS.objects.create(column1=data1,column2=data2)
Example inside of my file
12345678,good
12345678,bad

Categories

Resources