2011-02-14 118 views
1

我正在寫一些我真正發生的奇怪錯誤。django「重複的鍵值違反了唯一約束」主鍵

使用: 的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序列,這個問題就會出現。但是我在這張桌子裏沒有任何數據......沒有!我仍然得到這個錯誤..我不明白如何可能發生。

任何幫助將是偉大的!

+0

這可能是一個愚蠢的問題,但你確定id是autoincrementing,你可以直接檢查數據庫嗎?對不起,我從來沒有用過Django w/postgre。儘管我懷疑它是否與覆蓋save()方法有關。 – picus 2011-02-14 01:28:41

+0

有一點是肯定的,如果你還沒有數據:有多個插入發生。如果數據庫中只有一行,則不可能發生該錯誤。我猜想不知怎麼,保存在相同的數據上被調用兩次。 – 2011-02-14 03:33:04

回答

2

所以我搞清楚它是什麼。

這是因爲我在模型save()方法中做了一次黑客攻擊。我沒有使用屬性來計算emailLink的值,而是將模型保存了兩次。當發生這種情況時,我認爲Django會緩存模型,然後嘗試再次保存它。刪除自定義保存表單,並用此替換電子郵件鏈接

def constructEmailLink(self): 
    return "http://www.domain.com" + reverse('inthebackgroundSite.marketing.views.confirm', args=[self.id]) 

emailLink = property(constructEmailLink) 

訣竅。感謝你的幫助!

2

我認爲你仍然需要調用父對象(Form)的保存方法。在你的覆蓋方法的開始:

super(AddNewEmailForm, self).save() 
相關問題