django“重复键值违反唯一约束”主键

时间:2011-02-14 01:18:03

标签: django postgresql forms

我从我写的一个表单中得到了一些非常奇怪的错误。

使用: postgres 8.4 ubuntu 10.04 oython 2.6 django 1.2.4

基本上我有一个收集姓名和电子邮件地址的表格。但是我需要在另外两个表中创建虚拟行,以便我们可以跟踪它们。以下型号。

from django.db import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site


# Create your models here.

class company(models.Model):
    company = models.CharField(max_length=100)
    address = models.CharField(max_length=300)
    street = models.CharField(max_length=200)
    suburb = models.CharField(max_length=100)
    phone_number = models.CharField(max_length=15)
    contact_person = models.CharField(max_length=50,null=True)
    email = models.EmailField(max_length=100, null=True)
    latitude = models.CharField(max_length=10, null=True)
    longitude = models.CharField(max_length=11, null=True)


    def __unicode__(self):
        return unicode(self.company) + " - " + unicode(self.address) + " - " + unicode(self.contact_person) + " - " + unicode(self.email)


class campaign(models.Model):
    campaign_name = models.CharField(max_length=20)
    description = models.TextField(max_length=200)
    start_date = models.DateField(null=True)
    end_date = models.DateField(null=True)
    spent = models.DecimalField(decimal_places=2, max_digits=6)

    def __unicode__(self):
        return self.campaign_name


class contact_date(models.Model):
    CONTACT_CHOICES = (
                       ('email', 'email'),
                       ('person', 'person'),
                       ('twitter', 'twitter'),
                       ('facebook', 'facebook'),
                       ('Newsletter', 'Newsletter'),
                       )

    contacted = models.DateField()
    who = models.ForeignKey(User)
    how = models.CharField(max_length=15, choices=CONTACT_CHOICES)
    company = models.ForeignKey(company)
    campaign = models.ForeignKey(campaign)

    def __unicode__(self):
        return unicode(self.company) + " - " + unicode(self.contacted) + " - " + self.how  + " - " + unicode(self.campaign)


class questionaire_1(models.Model):
    SECTOR_CHOICES = (
                ('x', ''),
                ('0', 'Medical'),
                ('1', 'Vet'),
                ('2', 'Hair Dresser'),
                ('3', 'Beauty Salon'),
                ('4', 'Hospitality'),
                ('5', 'Retail'),
                ('6', 'Other')
                )
    IMPORTANCE_CHOICES = (
                    ('x', ''),
                    ('0', 'Very Important'),
                    ('1', 'Important'),
                    ('2', 'Moderately Important'),
                    ('3', 'Not That Important'),
                    ('4', 'Not at all important')
                    )
    ROYALTIES_CHOICES = (
                    ('x', ''),
                    ('0', 'no-I didnt know about them'),
                    ('1', 'no-but would like to'),
                    ('2', 'Yes'),
                    ('3', 'No, don\'t want to')
                    )
    SPEND_CHOICES = (
               ('x', ''),
               ('0', '$1000 or more'),
               ('1', '$500 or $1000'),
               ('2', '$200 to $500'),
               ('3', 'don\'t know'),
               ('4', 'Nothing')
               )
    INTERNET_CHOICES = (
               ('x', ''),
               ('0', 'Yes'),
               ('5', 'No')
               )
    INTERESTED_CHOICES = (
                    ('x', ''),
                    ('0', 'Yes'),
                    ('20', 'No')
                    )
    USEDNOW_CHOICES = (
                       ('x', ''),
                       ('Radio', 'Radio'),
                       ('Ipod', 'ipod'),
                       ('Streaming Radio', 'Streaming Radio'),
                       ('CDs', 'CDs')                       
                       )
    contact = models.ForeignKey(contact_date)
    sector = models.CharField(max_length=1, choices=SECTOR_CHOICES, null=True)
    importance = models.CharField(max_length=1, choices=IMPORTANCE_CHOICES, null=True)
    royalties = models.CharField(max_length=1, choices=ROYALTIES_CHOICES, null=True)
    spend = models.CharField(max_length=1, choices=SPEND_CHOICES, null=True)
    internet = models.CharField(max_length=1, choices=INTERNET_CHOICES, null=True)
    use_now = models.CharField(max_length=20, choices=USEDNOW_CHOICES, null=True)
    interested = models.CharField(max_length=2, choices=INTERESTED_CHOICES, null=True)
    score = models.IntegerField(null=True)
    comments = models.TextField(max_length=500, null=True)

    def calculate_score(self):
        if (self.sector == 'x') or (self.importance == 'x') or (self.royalties == 'x') or (self.spend == 'x') or (self.internet == 'x') or (self.interested == 'x'):
            self.sector = None
            self.importance = None
            self.royalties = None
            self.spend = None
            self.internet = None
            self.interested = None
            return None
        else:
            return int(self.sector) + int(self.importance) + int(self.royalties) + int(self.spend) + int(self.internet) + int(self.interested)

    def save(self, *args, **kwargs):
        self.score = self.calculate_score()
        super(questionaire_1, self).save(*args, **kwargs)

    def __unicode__(self):
        return unicode(self.contact)

class firstEmail(models.Model):
    contact = models.ForeignKey(contact_date)
    emailSent = models.BooleanField(default=False)
    whoTo = models.CharField(max_length = 50)
    MoreInformation = models.BooleanField(default=False)
    emailLink = models.CharField(max_length=75, null=True)
    comments = models.TextField(max_length=500, null=True)

    def constructEmailLink(self):
        return "infra.inthebackground.com" + reverse('inthebackgroundSite.marketing.views.confirm', args=[self.id])

    #watch out for potential DB hits on this one, as we are potentially saving twice.
    def save(self, *args, **kwargs):
        super(firstEmail, self).save(*args, **kwargs)
        self.emailLink = self.constructEmailLink()
        super(firstEmail, self).save(*args, **kwargs)

我的观点

    # Create your views here.


from django.shortcuts import render_to_response, get_list_or_404, get_object_or_404
from django.http import HttpResponse, HttpResponseRedirect
from inthebackgroundSite.marketing.models import campaign, company, contact_date, questionaire_1, firstEmail
from inthebackgroundSite.marketing.forms import AddNewEmailForm
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_protect
from django.template import RequestContext
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required





#######################################################
# view all details of contacts and their Questionaires
#
#######################################################

@    login_required
def viewAllDetails(request, contact_id):
    contactDetails = get_list_or_404(contact_date, id=contact_id)
    questionaireDetails = list(questionaire_1.objects.filter(contact=contact_id))
    firstEmailDetails = list(firstEmail.objects.filter(contact=contact_id))
    return render_to_response('marketing/viewAllDetails.html', 
                              {'contactDetails' : contactDetails, 'questionaireDetails' : questionaireDetails, 'firstEmailDetails' : firstEmailDetails})

#######################################################
# Takes a confirmation from the user that they are
# replying on behalf of a company. then submits a form
# that triggers emailMeAtLaunch()
#
#######################################################

@csrf_protect
d    ef confirm(request,firstEmail_id):
    firstEmailDetails = get_object_or_404(firstEmail, id=firstEmail_id)
    contactDetails = get_object_or_404(contact_date, id=firstEmailDetails.contact.id)
    companyDetails = get_object_or_404(company, id=contactDetails.company.id)
    campaignDetails = get_object_or_404(campaign, id=contactDetails.campaign.id)
    UserDetails = get_object_or_404(User, id=1)
    return render_to_response('marketing/confirm.html', {'firstEmailDetails': firstEmailDetails, 'companyDetails' : companyDetails}, context_instance=RequestContext(request))

########################################################
# This view updates the firstEmail table specified by the
# id passed in, setting MoreInformation to true.
#
########################################################

def emailMeAtLaunch(request,firstEmail_id):
    firstEmailDetails = get_object_or_404(firstEmail, id=firstEmail_id)
    contactDetails = get_object_or_404(contact_date, id=firstEmailDetails.contact.id)
    companyDetails = get_object_or_404(company, id=contactDetails.company.id)

    firstEmailDetails.MoreInformation = True
    firstEmailDetails.save()

    return render_to_response('marketing/thankyou.html', {'firstEmailDetails': firstEmailDetails, 'companyDetails' : companyDetails}, context_instance=RequestContext(request))

@csrf_protect
def addMeToMailingList(request):

    if request.method == 'POST':
        form = AddNewEmailForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('inthebackgroundSite.marketing.views.thankyou'))
    else:
        #print "not POST method"
        form = AddNewEmailForm()

    return render_to_response('marketing/addToMailingList.html', {'form': form }, context_instance=RequestContext(request))

def thankyou(request):
    return render_to_response('marketing/thankyou.html')

最后我的表格(抱歉所有代码......)

import datetime

from django import forms
from inthebackgroundSite.marketing.models import campaign, company, contact_date, firstEmail
from django.db import transaction
from django.template import RequestContext
from django.shortcuts import render_to_response, get_list_or_404, get_object_or_404
from django.contrib.auth import authenticate
from django.contrib.auth.models import User

class AddNewEmailForm(forms.Form):
    ContactPerson = forms.CharField(max_length=200)
    email = forms.EmailField()

    #def __init__(self, *args, **kwargs):
    #    self.firstEmail_id = kwargs.pop('firstEmail_id', None)

    #@transaction.commit_on_success
    def save(self):
        now = datetime.date.today()

        UserDetails = get_object_or_404(User, id=1)
        campaignDetails = get_object_or_404(campaign, id=1)
        #orginalFirstEmail = get_object_or_404(firstEmail, id=self.firstEmail_id)
        #originalContact = get_object_or_404(contact_date, id=orginalFirstEmail.contact.id)
        #originalCompany = get_object_or_404(company, id=originalContact.company.id)
        newCompany = company.objects.create(company = "unknown",
                                            address = "unknown",
                                            street = "unknown",
                                            suburb = "unknown",
                                            phone_number = "unknown",
                                            contact_person = self.cleaned_data['ContactPerson'],
                                            email = self.cleaned_data['email'],
                                            latitude = None,
                                            longitude = None
                                            )
        print str(newCompany.id) + ": " + unicode(newCompany)
        newContact = contact_date.objects.create(contacted = now,
                                                 who = UserDetails,
                                                 how = 'email',
                                                 company = newCompany,
                                                 campaign = campaignDetails
                                                 )
        print str(newContact.id) + ": " + unicode(newContact)
        newFirstEmail = firstEmail.objects.create(contact = newContact,
                                                  emailSent = False,
                                                  whoTo = "unknown",
                                                  MoreInformation = True,
                                                  comments = "This is a new addition to the mailing list that came from an unknown company.\n The company that this email was sent to is in the WhoTo",
                                                  )
        print str(newFirstEmail.id) + ": " + unicode(newFirstEmail)

我遇到的问题是

重复键值违反了唯一约束“marketing_firstemail_pkey”

现在,如果我直接将数据加载到postgres并且没有更新id的序列,那么通常会出现这个问题。但我这张表中没有任何数据......没有!我仍然得到这个错误..我不明白这是怎么发生的。

任何帮助都会很棒!

2 个答案:

答案 0 :(得分:2)

我认为你仍然需要调用父对象(Form)的save方法。在覆盖方法的开头:

super(AddNewEmailForm, self).save()

答案 1 :(得分:2)

所以我弄清楚它是什么。

这是因为我在模型save()方法中做了一次黑客攻击。我没有使用属性来计算emailLink的值,而是将模型保存两次。当发生这种情况时,我认为Django会缓存模型然后再次尝试保存它。删除自定义保存表单并用此

替换电子邮件链接
 def constructEmailLink(self):
    return "http://www.domain.com" + reverse('inthebackgroundSite.marketing.views.confirm', args=[self.id])

emailLink = property(constructEmailLink)

做了这个伎俩。谢谢你的帮助!