Django update_or_create()抛出'已经存在'

zsohkypk  于 12个月前  发布在  Go
关注(0)|答案(1)|浏览(118)

这里是我的models.py。注意,对于容量模型:'year','month','employee'是unique_together。

class Employee(models.Model):
    last_name = models.CharField('Nachname', max_length=200)
    first_name = models.CharField('Vorname', max_length=200)
    address = models.CharField('Strasse und Hausnummer', max_length=200)
    zip_code = models.IntegerField('PLZ', default=4000)
    place = models.CharField('Wohnort', max_length=200)
    birth_date = models.DateField('Geburtsdatum')
    entry_date = models.DateField('Startdatum')
    email = models.CharField(max_length=200)
    phone = models.CharField(max_length=15, blank=True)
    ahv_no = models.CharField('AHV Nummer', max_length=200, blank=True)
    HEBAMME = 'HEBAMME'
    PFLEGEFACHFRAU = 'PFLEGEFACHFRAU'
    JOB_CHOICES = [
        (HEBAMME, 'Hebamme'),
        (PFLEGEFACHFRAU, 'Pflegefachfrau'),
    ]
    job = models.CharField(
        max_length=20,
        choices=JOB_CHOICES,
        default=HEBAMME,
    )
    workload = models.IntegerField('Pensum', validators=[MaxValueValidator(100)], default=100)
    active = models.BooleanField(default=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=True,
        null=True,
        on_delete=models.CASCADE
        )    
    services = models.ManyToManyField(
        'customers.Service',
        default=1,
        blank=True
        )
    def __str__(self):
        return self.first_name + ' ' + self.last_name

class Capacity(models.Model):
    employee = models.ForeignKey(
        Employee,
        blank=True,
        null=True,
        on_delete=models.CASCADE
    )
    number_wobe = models.IntegerField(
        'Anzahl Wochenbett',
        default=0
    )
    year_choices = (
        (2023, '2023'),
        (2024, '2024'),
        (2025, '2025'),
    )
    month_choices = (
        (1, 'Januar'),
        (2, 'Februar'),
        (3, 'März'),
        (4, 'April'),
        (5, 'Mai'),
        (6, 'Juni'),
        (7, 'Juli'),
        (8, 'August'),
        (9, 'September'),
        (10, 'Oktober'),
        (11, 'November'),
        (12, 'Dezember'),
    )
    year = models.IntegerField(
        'Jahr',
        choices=year_choices)
    month = models.IntegerField(
        'Monat',
        choices=month_choices)

    class Meta:
        unique_together = ('year', 'month', 'employee')

字符串
views.py请注意,我的过滤器kwargs是year、month和employee(unique_together),要更新的项目是'number_wobe'。

def UpdateCreateCapacityView(request, year, month, employee_id):
    if request.method == 'POST':
        next = request.POST.get('next', '/')
        form = CapacityForm(request.POST)
        if form.is_valid():
            capacity = form['number_wobe'].value()
            cap, created = Capacity.objects.update_or_create(
                year=year,
                month=month,
                employee=employee_id,
                defaults={"number_wobe": capacity},
            )

            return HttpResponseRedirect(next)

    else:
        capacity = Capacity.objects.filter(year=year).filter(month=month).filter(employee=employee_id).values_list('number_wobe', flat=True)
        for item in capacity:
            capacity = item
        form = CapacityForm(initial={'employee': employee_id, 'year': year, 'month': month, 'number_wobe': capacity})

    return render(request,
                'planning/add_capacity.html',
                {'form': form})


add_capacity.html

{% extends 'dashboard/base.html' %}
{% load crispy_forms_tags %}

{% block title %}Kapazität verwalten{% endblock %}

{% block content %}
{% if user.is_authenticated %}

 <h1 class="title is-2">Kapazität verwalten</h1>

<form action="" method="post" novalidate>
  {% csrf_token %}
  {{ form|crispy }}
  <input type="hidden" name="next" value="{{ request.path }}">
  <input type="submit" value="Submit">
</form>

{% else %}
<h3 class="title is-3 has-text-centered has-text-weight-light">Du musst eingeloggt sein, um diese Seite zu sehen:</h3>
<br>
<div class="columns is-centered">
  <div class="colum is-half">
    <a class="button has-text-centered is-rounded is-primary is-large" href="{% url 'accounts:login' %}">Login</a>
  </div>
</div>
{% endif %}

{% endblock %}

**问题:**提交表单时,我得到一个'already exists'错误。当使用update_or_create()时,我希望它只是更新对象(如果它存在)。我(认为我)已经根据Django文档(https://docs.djangoproject.com/en/4.2/ref/models/querysets/#update-or-create)使用了该函数。

2eafrhcq

2eafrhcq1#

虽然您没有显示您的CapacityForm,但我相信ModelForm是您问题的根源,而不是您使用update_or_create()
当你为一个ModelForm调用.is_valid()方法时,它首先验证你定义的表单,然后验证Django文档中描述的模型本身。这意味着如果你提交一个有年份、月份和雇员的表单,is_valid()函数将抛出"* 已经存在 *“'错误。您可以尝试使用中断点进行验证,以显示表单在is_valid()方法之后已经失效。调用,或者在条件语句中使用print语句来显示它甚至从未被输入过。
我知道的两种处理方法是:
1.我链接的Django文档告诉你:
ModelForm.clean()方法设置一个标志,使模型验证步骤验证标记为unique、unique_together或unique_for_date的模型字段的唯一性|月|年
如果您想要覆写clean()方法并维持这个验证,您必须呼叫父类别的clean()方法。
您可以自己查看BaseModelForm定义来查看这个干净的方法,但也可以在CapacityForm中覆盖它,如下所示:

def clean(self):
    self._validate_unique = False
    return self.cleaned_data

字符串
这将跳过对is_valid()调用的唯一性验证,但请考虑在代码的其余部分中,这是否会在使用表单的地方导致错误,并且它 * 应该 * 检查唯一性。
1.一些stackoverflow的答案建议将其更改为标准的forms.Form而不是ModelForm。这样它就不会执行模型验证步骤。如果您的模型上有很多约束和验证逻辑,那么您将不得不在表单字段上重复这些操作,这可能会很烦人。

相关问题