IntegrityError:列中的空值.Django测试保存方法悖论

时间:2017-04-26 19:35:32

标签: python django django-models error-handling save

我正在为允许用户上传文件的视图添加一个附件,这在我使用runserver进行测试时非常有效。但是,当我使用Django测试用例时,我得到IntegrityError: null value in column "created_at" violates not-null constraint,其中created_at是一个DateTimeField。

class Proposal(IsPrimeMixin, PSortMixin, models.Model):
    number = models.OneToOneField(ProjectNumber, on_delete=models.CASCADE, primary_key=True)
    created_at = models.DateTimeField(auto_now_add=True)
    ...

悖论是,从父节省方法中引发IntegrityError错误的地方。

...
File "/Users/feldman/workspace/intranet/proposals/models.py", line 329, in save
    super(Proposal, self).save(*args, **kwargs)
...

但是,according to django此字段应为空,因为auto_now中设置了pre_save字段。当我使用runserver时,会重申这一点; self.created_at为空,直到调用父保存方法的第329行之后。只有在那之后它才有价值。

> /Users/feldman/workspace/intranet/proposals/models.py(329)save()
(Pdb) self.created_at
(Pdb) next
> /Users/feldman/workspace/intranet/proposals/models.py(330)save()
-> next_number.assigned_at = timezone.now()
(Pdb) next
> /Users/feldman/workspace/intranet/proposals/models.py(331)save()
-> next_number.save()
(Pdb) self.created_at
datetime.datetime(2017, 4, 26, 18, 45, 40, 65870, tzinfo=<UTC>)

因此,为什么在非测试用例中通常会填充IntegrityError

我正在运行Django 1.10

测试:

class ProposalTests(TestCase):
    def setUp(self):
        ...
        self.form_data = {
            'city': 'Test City',
            'gng_chance_of_winning': 'high',
            'gng_effort_required': 2,
            'market_area': self.marketarea.id,
            'project_director': self.proj_director.id,
            'project_manager': self.proj_manager.id,
            'project_type': 'PU',
            'role': self.cc.role,
            'title': self.cc.title,
            'ultimate_organization': self.ult_org.id,
            'ultimate_contact': self.ult_contact.id,
            'created_at': timezone.now()
        }

class TestProposalNewView(ProposalTests):

    def test_adding_proposal_documents(self):
        ProjectNumber.objects.create(number=72712)    
        self.client.login(username='testerton', password='bologna')
        with open('core/test_data/test_case.pdf') as pd:
            self.form_data.update({'conflict_check': self.cc.id, 'files': pd})
            response = self.client.post(reverse('proposals:new'), self.form_data)
            import pdb; pdb.set_trace()

模型的保存方法的相关部分,

def save(self, *args, **kwargs):
    log_entry = kwargs.pop('log_entry', True)
    if self.pk is None:
        next_number = ProjectNumber.objects.next_number()
        self.number = next_number
        super(Proposal, self).save(*args, **kwargs)   # line 329

和追溯

Internal Server Error: /proposals/new
Traceback (most recent call last):
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/core/handlers/exception.py", line 42, in inner
    response = get_response(request)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/Users/feldman/workspace/intranet/proposals/views.py", line 66, in proposal_new
    proposal.save()
  File "/Users/feldman/workspace/intranet/proposals/models.py", line 329, in save
    super(Proposal, self).save(*args, **kwargs)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/base.py", line 796, in save
    force_update=force_update, update_fields=update_fields)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/base.py", line 824, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/base.py", line 889, in _save_table
    forced_update)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/base.py", line 939, in _do_update
    return filtered._update(values) > 0
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/query.py", line 654, in _update
    return query.get_compiler(self.db).execute_sql(CURSOR)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1148, in execute_sql
    cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 835, in execute_sql
    cursor.execute(sql, params)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/feldman/.virtualenvs/intranettwopointoh/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
IntegrityError: null value in column "created_at" violates not-null constraint
DETAIL:  Failing row contains (456, null, 2017-04-26 18:59:03.693245+00, Test Case, , null, open, SO, f, PU, null, null, , f, f, f, f, f, f, f, high, 2, null, null, null, null, null, Test City, null, 456.

视图

@login_required
def proposal_new(request):
    recent_conflict_checks = None
    conflict_check = None
    has_proposal = False
    existing_proposals = None
    if request.method == 'POST':
        go_no_go = True
        prime = True
        if 'cancel' in request.POST:
            return HttpResponseRedirect(reverse('projects:list'))
        if 'conflict_check' in request.POST:
            try:
                conflict_check = ConflictCheck.objects.get(pk=int(request.POST['conflict_check']))
            except ValueError:
                pass
            else:
                go_no_go = conflict_check.is_go_no_go
                prime = conflict_check.is_prime
        form = forms.proposal_new_form_factory(request.POST, go_no_go=go_no_go, prime=prime)
        pdform = forms.ProposalDocumentForm(request.POST, request.FILES, prefix='proposal_docs')
        if form.is_valid() and pdform.is_valid():
            proposal = form.save(commit=False)
            proposal.created_by = request.user.employee
            try:
                proposal.save()  # line 66
            except NoProjectNumbers:
                messages.error(request, 'No project numbers remain in the database, please contact an administrator.')
            else:
                ...

表格工厂(其中AForm,BForm,CForm和&amp; DForm只是excludefieldsets的不同组合)

def choose_base_class(go_no_go, prime):
    if go_no_go and prime:
        return AForm
    elif go_no_go and not prime:
        return BForm
    elif not go_no_go and prime:
        return CForm
    elif not go_no_go and not prime:
        return DForm
    else:
        raise ValueError('How did this happen...')

def proposal_new_form_factory(*args, **kwargs):
    go_no_go = kwargs.get('go_no_go', True)
    prime = kwargs.get('prime', True)
    base_class = choose_base_class(go_no_go, prime)

    class ProposalNewForm(base_class):

        class Meta(base_class.Meta):
        # Add status to exclude
            base_class.Meta.exclude.append('status')
            # Add description for demographics and marketing fieldset
            fieldsets = deepcopy(base_class.Meta.fieldsets)
            marketing_fieldset = filter(lambda x: x[0] == 'Demographics and Marketing', fieldsets)[0]
            marketing_index = fieldsets.index(marketing_fieldset)
            fieldsets[marketing_index][1]['description'] = ('Either city or state is required for a new proposal.')

    return ProposalNewForm(*args, **kwargs)

很乐意提供更多需要的信息

0 个答案:

没有答案