freestyletin
freestyletin

Reputation: 43

Error: "'NoneType' object has no attribute..." when utilizing method for a self-referential foreign key

I'm developing my first Django project for practice, and I'm running to a problem with self-referential foreign keys.

I have an app called "units" in which there is a models.py:

from django.db import models

class Unit(models.Model):
    name = models.CharField(
        'Unit', 
        max_length=255, 
        blank=True
        )
    quantity_per = models.DecimalField(
        'Quantity Per', 
        max_digits=10, 
        decimal_places=5, 
        default=1
        )
    subunit = models.ForeignKey(
        'self', 
        blank=True, 
        null=True, 
        on_delete=models.SET_NULL, 
        related_name='+', 
        verbose_name="subunit"
        )
    abbreviation = models.CharField(
        'Abbreviation', 
        max_length=255, 
        blank=True
        )

    def unit_factor(self):
        return self.subunit.quantity_per * self.quantity_per

    def __str__(self):
        return self.name

And this is referred to in my rudimentary index template as so:

{% load static %}

<link rel="stylesheet" type="text/css" href="{% static 'units/style.css' %}"/>

{% if unit_list %}
  <ul>
    {% for unit in unit_list %}
    <li>{{ unit.name }} - {{ unit.subunit }} - {{ unit.subunit.quantity_per }} - {{ unit.unit_factor }}</li>
    {% endfor %}
  </ul>
{% else %}
  <p>No units are available.</p>
{% endif %}

When I runserver and navigate to the "units" url, I get the following error:

'NoneType' object has no attribute 'quantity_per'

I think this has something to do with me creating the method within the same class as the self-referential foreignkey and the child instance not being completely instantiated yet? But I'm sure my lack of programming knowledge is showing. How can I perform operations like this correctly within this relationship?

UPDATE I'm marking this solved, but I wanted to add my view as per @alexandre-cox request:

from django.template import loader
from django.views import generic

from .models import Unit

class IndexView(generic.ListView):
    template_name = 'units/index.html'

    def get_queryset(self):
        return Unit.objects.order_by('name')

Thanks for your patience in answering this!

Upvotes: 1

Views: 509

Answers (1)

JPG
JPG

Reputation: 88569

The exception raises because of your Unit instance does not have any child and your code tries to access child's quantity_per attribute.

So, change unit_factor() method as below,

def unit_factor(self):
    if hasattr(self, 'subunit') and hasattr(self.subunit, 'quantity_per'):
        return self.subunit.quantity_per * self.quantity_per
    return 0  # Default Value

Refer the python builtin function hasattr()

Upvotes: 2

Related Questions