1

SITUATION

  • I am modifying this GitHub project from this YouTube Series and this is a demo how the original application runs.
  • My goal is to add settings option for Merchant(in the code Admin or AdminUser) accounts in the marketplace, because in the original project only buyers have the option to add image and their contact details.

CODE

model.py

#database table create
class Customer(models.Model):
    #empty fields accept - null=True
    user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=200, null=True)
    phone = models.CharField(max_length=200, null=True)
    email = models.CharField(max_length=200, null=True)
    profile_pic = models.ImageField(default="profile1.png", null=True, blank=True)
    date_created = models.DateTimeField(auto_now_add=True, null=True)

    #show customer name in admin panel
    def __str__(self):
        return self.name


class Adminuser(models.Model):
    #empty fields accept - null=True
    user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=200, null=True)
    phone = models.CharField(max_length=200, null=True)
    email = models.CharField(max_length=200, null=True)
    profile_pic = models.ImageField(default="profile1.png", null=True, blank=True)
    date_created = models.DateTimeField(auto_now_add=True, null=True)

    #show customer name in admin panel
    def __str__(self):
        return self.name

url.py

from django.urls import path
from django.contrib.auth import views as auth_views
from . import views

urlpatterns = [
    ...
    path('customer/<str:pk_test>/', views.customer, name="customer"),
    path('adminuser/<str:pk_test>/', views.adminuser, name="adminuser"),
    ...
]

views.py

#CUSTOMER_ONLY PROFILE SETTINGS
@login_required(login_url='login')
@allowed_users(allowed_roles=['customer'])
def accountSettings(request):
    customer = request.user.customer
    form = CustomerForm(instance=customer)
    if request.method == 'POST':
        form = CustomerForm(request.POST, request.FILES,instance=customer)
        if form.is_valid():
            form.save()
    context = {'form':form}
    return render(request, 'accounts/account_settings.html', context)



#ADMIN_ONLY PROFILE SETTINGS
@login_required(login_url='login')
@allowed_users(allowed_roles=['admin'])
def adminSettings(request):
    admin = request.user.admin
    form = AdminForm(instance=admin)
    if request.method == 'POST':
        form = AdminForm(request.POST, request.FILES,instance=admin)
        if form.is_valid():
            form.save()
    context = {'form':form}
    return render(request, 'accounts/account_admin_settings.html', context)

forms.py

from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms

from .models import *

class CustomerForm(ModelForm):
    class Meta:
        model = Customer
        fields = '__all__'
        exclude = ['user']

class AdminForm(ModelForm):
    class Meta:
        model = Adminuser
        fields = '__all__'
        exclude = ['user']

navbar.html

...
<li class="nav-item">
  <a class="nav-link" href="{% url 'adminsettings' %}">SettingsAdmin</a>
</li>
...

account_admin_settings.html

{%  extends 'accounts/main.html' %}
{% load static %}
{% block content %}

<style>
    .profile-pic{
        max-width: 200px;
        max-height:200px;
        margin: 0 auto;
        border-radius: 50%;
    }
</style>
<!-- -->
<br>
<div class="row">
    <div class="col-md-3">
        <div class="card card-body">
            <a class="btn btn-warning" href="{% url 'dashboard' %}"> &#8592; Back to Profile</a>
            <hr>
            <h3 style="text-align: center">Account Settings</h3>
            <hr>
            <img class="profile-pic" src="{{request.user.customer.profile_pic.url}}" >

        </div>
    </div>
    <div class="col-md-9">
        <div class="card card-body">

            <form method="POST" action="" enctype="multipart/form-data">
                {% csrf_token %}
                {{form.as_p}}

            <input class="btn btn-primary" type="submit" name="Update Information">
            </form>
        </div>
    </div>
</div>

ERROR

AttributeError at /accounts/adminsettings/
'User' object has no attribute 'admin'
Request Method: GET
Request URL:    http://127.0.0.1:8000/accounts/adminsettings/
Django Version: 3.0
Exception Type: AttributeError
Exception Value:    
'User' object has no attribute 'admin'
Exception Location: /Users/computer/ven/lib/python3.7/site-packages/django/utils/functional.py in inner, line 225
Python Executable:  /Users/computer/ven/bin/python3
Python Version: 3.7.3
Python Path:    
['/Users/computer/project',
 '/Users/computer/anaconda3/lib/python37.zip',
 '/Users/computer/anaconda3/lib/python3.7',
 '/Users/computer/anaconda3/lib/python3.7/lib-dynload',
 '/Users/computer/ven/lib/python3.7/site-packages']
Server time:    Wed, 17 Jun 2020 22:17:12 +0000

TRIED SOLUTIONS

MY FUNCTION ANME  
    try:
        # MY ORIGINAL CODE
    except ObjectDoesNotExist:
        # and what goes here?????
  • @xyres updated view.py def adminSettings(request):
#ADMIN_ONLY PROFILE SETTINGS ''' '''
@login_required(login_url='login')
@allowed_users(allowed_roles=['admin'])
def adminSettings(request):
    try:
        admin = requset.user.admin
        form = AdminForm(instance=admin)
        if request.method == 'POST':
            form = AdminForm(request.POST, request.FILES,instance=admin)
            if form.is_valid():
                form.save()
        context = {'form':form}
        return render(request, 'accounts/account_admin_settings.html', context)
    except ObjectDoesNotExist:
        print("Either the entry or blog doesn't exist.")
        return render(request, 'accounts/account_admin_settings.html', context)
  • ERROR: File "/Users/computer/project/accounts/views.py", line 106 form = AdminForm(instance=admin) ^
    • Hanged back the views.py and models.py back to it's original state and now I get a new error (after makemigration migrate changes)
NameError at /accounts/adminsettings/
name 'requset' is not defined
Tom Carrick
  • 6,349
  • 13
  • 54
  • 78
sogu
  • 2,738
  • 5
  • 31
  • 90

1 Answers1

3

From OneToOneField's documentation:

If you do not specify the related_name argument for the OneToOneField, Django will use the lowercase name of the current model as default value.

So, you'll have to access the related Adminuser instance as:

request.user.adminuser

If you want to access it using just admin, as mentioned in the docs, you'll have to make use of the related_name argument:

class Adminuser(models.Model):
    user = models.OneToOneField(User, related_name='admin' ...)
    ...

# request.user.admin will work now

Update

RelatedObjectDoesNotExist exception is raised when the related object doesn't exist in the database (this is often the case when related field can be null). Since there's no AttributeError this time, that means Django did recognise the admin attribute; so, that issue is fixed.

You'll have to handle RelatedObjectDoesNotExist exception everywhere you're accessing the related attribute.

from django.core.exceptions import ObjectDoesNotExist

try:
    admin = requset.user.admin
except ObjectDoesNotExist:
    admin = # set some other value ...
xyres
  • 20,487
  • 3
  • 56
  • 85
  • I have done to correction and added your code part to the model function but I still get the error see at "TRIED SOLUTIONS". – sogu Jun 18 '20 at 17:41
  • I have added both ```request.user.adminuser``` AND ```user = models.OneToOneField(User, related_name='admin' ...)``` and applied migrarionas in 2 step after both things in my codebase. – sogu Jun 18 '20 at 17:48
  • @sogu So the `AttributeError` has been solved. `RelatedObjectDoesNotExist` exception is raised when the related object doesn't exist. In this case, there's no related `admin` instance in the database. Handle this exception using `ObjectDoesNotExist` as shown here: https://docs.djangoproject.com/en/3.0/ref/models/querysets/#django.db.models.query.QuerySet.get – xyres Jun 18 '20 at 18:05
  • @sogu Or here's a better example to handle this exception: https://stackoverflow.com/a/42821464/1925257 – xyres Jun 18 '20 at 18:12
  • Added question the stackoverflow.com/a/42821464/1925257 post usage to the "Tried Solutions" – sogu Jun 18 '20 at 18:14
  • Updated my post in the "Tried Solutions" the views.py function is not working in it's current condition – sogu Jun 18 '20 at 18:32
  • @sogu As I see it, your original issue was solved. Please open a new question for other issues. https://meta.stackexchange.com/q/39223 – xyres Jun 20 '20 at 04:38
  • Ok. I will do open a new one. – sogu Jun 20 '20 at 10:30