views:

72

answers:

2

The following code is being used by the admin to save a Loan object

import uuid

from django.db import models
from django.contrib.auth.models import User
from apps.partners.models import Agent

# Create your models here.
class Loan(models.Model):
    """ This is our local info about the loan from the LOS """
    guid = models.CharField(max_length=64, blank=True)
    number = models.CharField(max_length=64, blank=True)
    name = models.CharField(max_length=64)
    address = models.CharField(max_length=128)
    address2 = models.CharField(max_length=128, null=True, blank=True)
    city = models.CharField(max_length=32)
    state = models.CharField(max_length=2)
    zipcode = models.CharField(max_length=9)
    borrowers = models.ManyToManyField(User, related_name='loan_borrowers')
    officers = models.ManyToManyField(Agent, related_name='loan_officers')

    def __unicode__(self):
        return "%s %s, %s  %s" % (self.address, self.city, self.state, self.zipcode)

    def save(self, force_insert=False, force_update=False, using=None):
        """ Adds a GUID if one is not present """
        if self.guid == None:
            self.guid = uuid.uuid4().hex
        super(Loan, self).save(force_insert, force_update, using)

When I get to the super line, I get:

TypeError: super() argument 1 must be type, not None

The save call is made from options.py line 597 and at that point obj is known to be a Loan object.

if I replace the super() line with

    super(type(self), self).save(force_insert, force_update, using)

all is well. What is going on here?

The rest of the file is:

class Need(models.Model):
    from apps.public_portal.models import DocumentType
    loan = models.ForeignKey(Loan, null=False, blank=False)
    borrower = models.ForeignKey(User, null=False, blank=False)
    doctype = models.ForeignKey(DocumentType, null=False, blank=False)
    satisfied = models.DateTimeField(null=True, blank=True)
    first_request = models.DateTimeField(auto_now_add=True)
    last_request = models.DateTimeField(null=True, blank=True)

    def __unicode__(self):
        return "%s from %s for %s" % (self.doctype.name, self.borrower.get_full_name(), self.loan)

So I don't see how anything is binding Loan to None

A: 

Something else is rebinding Loan to None. Look further down, or maybe in another module. Also, you don't want type(self) since that will fail for any grandchildren or further.

Ignacio Vazquez-Abrams
I agree I don't want type(self), that is part of the reason for the question. I amended the question to show the whole file. What is going on?
Mark0978
A: 

The Django developers offer a pattern for overriding the model save() method. Using that pattern, the implementation for your save() method should be:

def save(self, *args, **kwargs):
    if self.guid == None:
        self.guid = uuid.uuid4().hex
    super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.

Let me offer a different approach: use signals!

Instead of trying to override the save() method, use a pre-save signal to initialize the guid field prior to the record being inserted/updated. Add the following code to your model.py file:

def add_loan_guid( sender, instance, **kwargs ):
    """Ensure that a Loan always has a guid"""
    if instance.guid == None:
        instance.guid = uuid.uuid4().hex

pre_save.connect( add_loan_guid, sender=Loan )

Now, any time that a Loan object is saved, but before it is persisted to the database, add_loan_guid() will be called, and if the Loan instance has no guid set, a new one will be created.

Craig Trader