4

I added A Many2Many field in one of my forms and now I am getting an IntegrityError on submit. The exact error text is

IntegrityError at /add_person/ hireterm_person.mail_lists may not be NULL

It worked fine until I added the new field. When I look at the POST data on the debug change, I see it being passed, so I don't know where the break occurs.

Models

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

class Mailists(models.Model):
    name = models.CharField(blank=True, max_length=100)
    email = models.CharField(blank=True, max_length=100)

    def __unicode__(self):
        return u'%s' % (self.name)

class Person(models.Model):
    ROLE_CHOICES = (
        ('Mrkt', 'Marketing'),
        ('Fin/Off', 'Finance / Office'),
        ('Care', 'Care'),
        ('Sales', 'Sales'),
        )
    ROLE_TYPE = (
        ('Full', 'Full Time'),
        ('Part', 'Part Time'), 
        ('Intern', 'Intern'),
        )

    first_name = models.CharField(blank=True, max_length=100)
    last_name = models.CharField(blank=True, max_length=100)
    date_added = models.DateField(auto_now_add=True)
    date_start = models.DateField(auto_now=False)
    role = models.CharField(max_length=100, default = "", choices = ROLE_CHOICES)
    manager = models.ForeignKey('self', limit_choices_to = {'is_manager': True}, null=True, blank=True)
    title = models.CharField(blank=True, max_length=100)
    role_type = models.CharField(max_length=100, default = "", choices = ROLE_TYPE)
    laptop_needed = models.BooleanField(default=True)
    phone_needed = models.BooleanField(default=True)
    desk_loco = models.CharField(blank=True, max_length=100)
    mail_lists = models.ManyToManyField(Mailists, blank=True)
    notes = models.CharField(blank=True, max_length=500)
    is_manager = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

class PersonForm(ModelForm):
    mail_lists = forms.ModelMultipleChoiceField(queryset=Mailists.objects.all(), widget=forms.CheckboxSelectMultiple(), required=False)
    class Meta:
        model = Person

EDIT

I added mail_lists = request.POST.getlist('mail_lists'). When I add a print to this, the list returned is all of the check boxes, put the POST data is still a single string, the last box checked.

Views

from hireterm.models import Person, Mailists, PersonForm
from django.shortcuts import get_object_or_404, render
from django.template import Context, loader
from django.http import HttpResponseRedirect, HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login
from django.contrib.auth import logout
from django.core.mail import send_mail

@login_required
def home(request):
    return render(request, 'hireterm/home.html')

def add_person(request):
    if request.method == 'POST':
        mail_lists = request.POST.getlist('mail_lists') 
        person_form = PersonForm(request.POST)
        if person_form.is_valid(): 
            person_form.save()
            return HttpResponseRedirect('/new_hire') # Redirect after POST

    else:
        person_form = PersonForm() # An unbound form

    return render(request, 'hireterm/additem.html', {
        'form': person_form,
    })
Kevin
  • 4,211
  • 10
  • 33
  • 40
  • 1
    I believe the issue is I am not returning a list. The post data I get, no matter how many boxes are checked, is the number of the last box checked in unicode, eg u'3'. – Kevin Aug 15 '13 at 15:13

1 Answers1

11

On your field:

mail_lists = models.ManyToManyField(Mailists, blank=True)

you have added blank=True to the field, but not null=True. This means that your DB is expecting that field to have a value. So when it doesn't you get an error.

null

If True, Django will store empty values as NULL in the database. Default is False. Note that empty string values will always get stored as empty strings, not as NULL. Only use null=True for non-string fields such as integers, booleans and dates. For both types of fields, you will also need to set blank=True if you wish to permit empty values in forms, as the null parameter only affects database storage (see blank).

blank

If True, the field is allowed to be blank. Default is False.

Note that this is different than null. null is purely database-related, whereas blank is validation-related. If a field has blank=True, form validation will allow entry of an empty value. If a field has blank=False, the field will be required.

Here are some other explanations:

Community
  • 1
  • 1
Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
  • I get the error when I have a checkbox checked off, which I assume to not be null. – Kevin Aug 15 '13 at 14:20
  • Also, that is after I added null=True to mail_lists – Kevin Aug 15 '13 at 14:26
  • Did you migrate the DB after adding `null=True`? – Timmy O'Mahony Aug 15 '13 at 15:49
  • Or if you're in dev, just need to syncdb again. Btw, "a checkbox checked off" doesn't get sent along with the request (so its value is `null`, check that with pdb or inspect your `request.POST` dict), which is not what `blank=True` field expects (at least a blank value) – Samuele Mattiuzzo Aug 15 '13 at 15:52
  • I am in dev. I did sync the db after adding it, I ran validate, sql hireterm, syncdb. I still get the same error. – Kevin Aug 15 '13 at 15:58
  • @SamueleMattiuzzo I have checked the contents of the dict, and if I check of say, the first and third checkboxes, the dict contains a list of those. SO I can't figure out why this is returning a null value – Kevin Aug 15 '13 at 19:45