Rileywiley
Rileywiley

Reputation: 139

Django: Attribute error on custom Save()

I am having an issue creating a custom slug for the protocol model below. The custom save function to create the slug works fine with I do in the Admin page but not when I use the add_protocol view below. The Study model has a field called protocolnumber so I am not sure why it thinks it does not.

I think it has something to do with how the view is set up, i.e. the commit = false and then the commit=true. Maybe because on the commit = False it is trying to assign a slug value using info from the study model prior to it being assigned. Not sure how to fix that though. Thanks!

The Models:

class Study(models.Model):
        protocolnumber = models.CharField(max_length=100, blank=True, null=True)


class Protocol(models.Model):
    study = models.ForeignKey(Study, null=True)
    version = models.DecimalField(max_digits=3, decimal_places=1, null=True)
    slug = models.SlugField(max_length=200, blank=True, null=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.study.protocolnumber)+'-V'+slugify(self.version)
            super(Protocol, self).save(*args, **kwargs)

The View:

def add_protocol(request,  study_slug):
    study = get_object_or_404(Study, slug=study_slug)
    if request.method == 'POST':
        new_protocol = AddProtocol(request.POST, request.FILES)
        if new_protocol.is_valid():
            new_protocol.save(commit=False)
            new_protocol.study = study
            new_protocol.save()
            return HttpResponseRedirect(reverse('studies:studydetails', args=(study.slug,)))
        else:
            HttpResponse('Something is messed up')
    else:
        new_protocol = AddProtocol()
        return render(request, 'studies/addprotocol.html', {'new_protocol': new_protocol, 'study': study})

The Error:

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/studies/lilly-a4/add-protocol/

Django Version: 1.8.7
Python Version: 3.5.0
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'studies',
 'account')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware')


Traceback:
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/RickyD/PycharmProjects/StudyTrack/studies/views.py" in add_protocol
  112.             new_protocol.save()
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/forms/models.py" in save
  459.                              construct=False)
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/forms/models.py" in save_instance
  105.         instance.save()
File "/Users/RickyD/PycharmProjects/StudyTrack/studies/models.py" in save
  92.             self.slug = slugify(study.protocolnumber)+'-V'+slugify(self.version)

Exception Type: AttributeError at /studies/lilly-a4/add-protocol/
Exception Value: 'NoneType' object has no attribute 'protocolnumber'

Upvotes: 0

Views: 432

Answers (1)

Aaron Lelevier
Aaron Lelevier

Reputation: 20818

You are allowing NULL for the study ForeignKey, so like @karthikr said, you need to handle this gracefully. One way to do this would be:

class Protocol(models.Model):
    study = models.ForeignKey(Study, null=True)
    version = models.DecimalField(max_digits=3, decimal_places=1, null=True)
    slug = models.SlugField(max_length=200, blank=True, null=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            protocolnumber = self.study.protocolnumber if self.study else ""
            self.slug = slugify(protocolnumber)+'-V'+slugify(self.version)
            super(Protocol, self).save(*args, **kwargs)

Upvotes: 1

Related Questions