I am creating a Django app. I will write the short summary of the system how it is supposed to work and then I will share my code.
When user (student) will go to the performance_calculator.html
he/she will see a textbox where he/she will have to enter the relevant subject name. After entering the subject name, he/she will click 'Calculate' button, on the other side (server-side) the entered name will be taken and the system will search the detail (progress) of that subject of that user (student) from the Detail Model using the subject name and that user name as filters. After getting the the progress detail, each value in the detail will be assigned to a separate single variable. Those variables will be passed as parameters to fuzz_algo()
function (a Fuzzy Logic Algorithm to calculator Performance), after getting the result, result will be forward to Client Side (Front End) using Django Messages Module.
This was the summary, now I get the error at the step when the system tries to get the progress details of the subject (whose name was entered by user) of the user (student who is using the system). and the Error is AttributeError: 'NoneType' object has no attribute 'get'
. I know this error happens when we receive None
from somewhere and we try to get something from None
. But I have populated the Detail Model along with the Subject Model using the Admin Panel (screenshots are attached). I don't know why I am getting None
and due to None
, this AttributeError
.
My views.py
def performanceCalculator(request):
skype = 0
internal_course = 0
prg_lab = 0
mid_marks = 0
final_marks = 0
sub = 0
if request.method == 'POST':
performance_form = PerformanceCalculatorForm(request.POST)
if performance_form.is_valid():
performance_form.save()
sub = performance_form.cleaned_data.get('subject')
skype = Detail.objects.filter(subject__subject=sub, user__username=User.username).values().first().get('skype_session_attendance')
internal_course = Detail.objects.filter(subject__subject=sub, user__username=User.username).values().first().get('internal_course_marks')
prg_lab = Detail.objects.filter(subject__subject=sub, user__username=User.username).values().first().get('programming_lab_activity')
mid_marks = Detail.objects.filter(subject__subject=sub, user__username=User.username).values().first().get('mid_term_marks')
final_marks = Detail.objects.filter(subject__subject=sub, user__username=User.username).values().first().get('final_term_marks')
result = fuzz_algo(skype, internal_course, prg_lab, mid_marks, final_marks)
messages.success(request, result)
return redirect('performance_calculator')
else:
performance_form = PerformanceCalculatorForm()
context = {
'performance_form': performance_form
}
return render(request, 'users/performance_calculator.html', context)
My models.py
class Subject(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
subject = models.CharField(max_length=100)
def __str__(self):
return '{} ({})'.format(self.subject, self.user.username)
class Detail(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
subject = models.OneToOneField(Subject, on_delete=models.CASCADE)
skype_session_attendance = models.FloatField()
internal_course_marks = models.FloatField()
programming_lab_activity = models.FloatField()
mid_term_marks = models.FloatField()
final_term_marks = models.FloatField()
def __str__(self):
return f'{self.subject, (self.user.username)} Details'
class Sub(models.Model):
s = models.CharField(max_length=100
My forms.py
class PerformanceCalculatorForm(forms.ModelForm):
subject = forms.CharField(max_length=100)
class Meta:
model = Sub
fields = ['subject']
My template (users/performance_calculator.html)
{% if not request.user.is_superuser and not request.user.is_staff %}
<div class="account-heading">
<h2>
Performance Calculator
</h2>
</div>
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4"></legend>
{{ performance_form|crispy }}
</fieldset>
<div class="from-group">
<button class="btn btn-outline-info" type="submit">Calculate</button>
</div>
</form>
</div>
{% endif %}
This is the full error that I get:
AttributeError at /esacp/performance-calculator/
'NoneType' object has no attribute 'get'
Request Method: POST
Request URL: http://localhost:8000/esacp/performance-calculator/
Django Version: 3.0.3
Exception Type: AttributeError
Exception Value:
'NoneType' object has no attribute 'get'
Exception Location: C:\Users\khubi\OneDrive\Desktop\FYP\test_phase\users\views.py in performanceCalculator, line 61
Python Executable: C:\environments\bsse_fyp\Scripts\python.exe
Python Version: 3.8.1
Python Path:
['C:\\Users\\khubi\\OneDrive\\Desktop\\FYP\\test_phase',
'C:\\Users\\khubi\\AppData\\Local\\Programs\\Python\\Python38-32\\python38.zip',
'C:\\Users\\khubi\\AppData\\Local\\Programs\\Python\\Python38-32\\DLLs',
'C:\\Users\\khubi\\AppData\\Local\\Programs\\Python\\Python38-32\\lib',
'C:\\Users\\khubi\\AppData\\Local\\Programs\\Python\\Python38-32',
'C:\\environments\\bsse_fyp',
'C:\\environments\\bsse_fyp\\lib\\site-packages']
Server time: Thu, 14 May 2020 11:55:41 +0000
Now, below are the screenshots of Admin Panel showing the populated Subject and Detail model: This is the main Django Admin Panel, see the actions at the right side?
This is the Subject Model, see 4 subjects are added, 2 of one student and 2 of other.
This is the Detail Model of one Subject of the user (student). See the details are entered and fields are not None
or empty
Now I don't understand, why am I getting the error where there is nothing empty.
P.S. Yes, I logged in with the same user (student) whose subject detail is populated in the screenshot above. If you see in Template, I have if condition
at start that if the user is not staff and not superuser, only then that form will be shown. So it's obvious with the Django Admin Panel logged in, i won't see that Performance Calculator form, I will only see the form if I am logged in with the regular account. But I am still getting the error.
Clarify: By looking this time at your entire code, you have data inserted to the database already, and your form is to only perform a GET to those data ... So for performance, the form should not be saved (as it will be creating new object every time you POST). And this means that a better approach for this should be coded as a GET instead of a POST...
but lets say this is a special case and you want to do that because you want to... This time I will directly modify your code, it is a headache at first watch because its querying too much and therefore VERY inefficient.
views.py
def performanceCalculator(request):
if request.method == 'POST':
performance_form = PerformanceCalculatorForm(request.POST)
if performance_form.is_valid():
#performance_form.save() #dont save because you dont need to.
#just process it by getting the data
sub = performance_form.cleaned_data['subject']
detail = Detail.objects.all().filter(user=request.user, subject=sub).first()
#get the unique object that matches the filters
#and I think what is causing you the Nonetype error is your queries
#(I saw filter(subject__subject=...) and the OneToOneField doesn't
#behave the same as a ForeignKey and that may be the case.)
#now fetch every field into the function
result = fuzz_algo(detail.skype_session_attendance, detail.internal_course_marks, detail.programming_lab_activity, detail.mid_term_marks, detail.final_term_marks)
messages.success(request, result) #if it raises int related error, include the str filter later.
return redirect('performance_calculator')
else:
performance_form = PerformanceCalculatorForm()
context = {
'performance_form': performance_form
}
return render(request, 'users/performance_calculator.html', context)
EDIT: Forgot to add this part
And in your models.py ... It doesn't make much sense to have the model Subject
and it is cause to have 2 user relation...
so a cleaner model would be:
#removed the Subject model
class Detail(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
subject = models.CharField(max_length=15) #modified to be a CharField
skype_session_attendance = models.FloatField()
internal_course_marks = models.FloatField()
programming_lab_activity = models.FloatField()
mid_term_marks = models.FloatField()
final_term_marks = models.FloatField()
def __str__(self):
return f'{self.subject, (self.user.username)} Details'
#also the Sub class
EDIT: Add the .first()
to get the first object on queryset