jixad
jixad

Reputation: 65

RelatedObjectDoesNotExist Exception

I tried to define prefix of signing in user, but I got this exception RelatedObjectDoesNotExist. The thing is django cannot find user Student and Parent(Exception Value: User has no student)

I want to render different templates according to user's type

models.py

from django.db import models
from django.contrib.auth.models import User


# Create your models here.


class Teacher(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    prefix = 't'

    def __str__(self):
        return self.user.first_name + ' ' + self.user.last_name


class Student(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    parent = models.ForeignKey('Parent', null=True)
    prefix = 's'

    def __str__(self):
        return self.user.first_name + ' ' + self.user.last_name


class Parent(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    prefix = 'p'

    def __str__(self):
        return self.user.first_name + ' ' + self.user.last_name

views.py

def sign_in(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_login = User.objects.get(username=username)
        user = authenticate(username=username, password=password)
        if user is not None:
            login(request, user_login)
            if user_login.student.prefix == 'S':
                return render(request, 's.html')
            if user_login.teacher.prefix == 'T':
                return render(request, 't.html')
            if user_login.parent.prefix == 'P':
                return render(request, 'p.html')
        else:
            return render(request, 'index.html', {'error': True})
    else:
        return render(request, 'index.html')
System check identified no issues (0 silenced).
May 20, 2017 - 21:43:51
Django version 1.11.1, using settings 'e_diary.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[20/May/2017 21:43:56] "GET / HTTP/1.1" 200 983
Internal Server Error: /sign_in/
Traceback (most recent call last):
  File "C:\Users\USER\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\exception.py", line 41, in inner
    response = get_response(request)
  File "C:\Users\USER\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\USER\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\USER\Desktop\e_diary\electronic_diary\views.py", line 29, in sign_in
    if user_login.teacher.prefix == 'T':
  File "C:\Users\USER\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\db\models\fields\related_descriptors.py", line 406, in __get__
    self.related.get_accessor_name()
django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist: User has no teacher.
[20/May/2017 21:44:02] "POST /sign_in/ HTTP/1.1" 500 70872

Upvotes: 3

Views: 8049

Answers (1)

zaidfazil
zaidfazil

Reputation: 9245

You could set a related_name to the field user in the Student, Teacher tables like this,

user = models.OneToOneField(User, related_name='student')

Also, you need to make sure that for a user , the corresponding student, parent, model is created.

Also, you are checking the prefix to an upper case letter, where in your model they are lower case. Python is strictly case-sensitive.

I think you need to change the if statement too,

try:
    if user_login.student.prefix == 'S'
        return render(request, 's.html')
except:
    try:
        if user_login.teacher.prefix == 'T'
            return render(request, 't.html')
    except:
        if user_login.parent.prefix == 'P':
            return render(request, 'p.html')

Because, the way in your view, every if statement is encountered during the view. Then if the user is Teacher, then it has no student object. Then, Django raises error. So better is to use a try-except combination for the purpose.

Also, from your code, I came up with a suggestion about Student, Teacher, Parent models. You could use a single Model Profile, with two flags is_teacher, is_parent and a default null ForeignKey field, which is set only if the is_parent flag is True, rather than repeatedly creating tables in the database. But, this is only a suggestion, as in your approach the Student, Teacher, Parent can be distinguished easily, though it takes up more storage space.

Upvotes: 3

Related Questions