UNIQUE constraint failed: members_activemember.member_id onetoonefield Django
Я получаю это сообщение об ошибке. Я не уверен, почему? В нем говорится, что оно появляется после сохранения моей формы из функции обновления в моем файле views.py.
Ошибка интеграции:
IntegrityError at /update/8
UNIQUE constraint failed: members_activemember.member_id
Request Method: POST
Request URL: https://topxgym.pythonanywhere.com/update/8
Django Version: 4.1
Exception Type: IntegrityError
Exception Value:
UNIQUE constraint failed: members_activemember.member_id
Exception Location: /home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/sqlite3/base.py, line 357, in execute
Raised during: members.views.update
Python Executable: /usr/local/bin/uwsgi
Python Version: 3.9.5
Python Path:
['/var/www',
'.',
'',
'/var/www',
'/usr/local/lib/python39.zip',
'/usr/local/lib/python3.9',
'/usr/local/lib/python3.9/lib-dynload',
'/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages',
'/home/topxgym/.virtualenvs/env/topxgym']
Server time: Tue, 23 Aug 2022 00:55:22 +0300
TrackBack
Это две мои модели Member и ActiveMember. Здесь используется поле OneToOneField, потому что у члена может быть только одно членство, дата активации, дата окончания и статус. Но я подозреваю, что ошибка Unique возникает из-за поля OneToOneField, потому что обновление смешивает идентификаторы, возможно? И члену назначается несколько членств? Это мое лучшее предположение. models.py
class Member(models.Model):
full_name = models.CharField(max_length=125, unique=True)
email = models.EmailField(max_length=125, blank=True, null=True)
phone = models.CharField(max_length=20)
detail = models.CharField(max_length=256, blank=True, null=True)
image = models.ImageField(max_length= 256, upload_to='media', null=True, blank=True)
date_created = models.DateTimeField(default=django.utils.timezone.now)
class Meta:
verbose_name_plural = "All Members"
def __str__(self):
return str(f"{self.full_name}")
def save(self, *args, **kwargs):
# delete old file when replacing by updating the file
try:
this = Member.objects.get(id=self.id)
if this.image != self.image:
this.image.delete(save=False)
except: pass # when new photo then we do nothing, normal case
super(Member, self).save(*args, **kwargs)
class ActiveMember(models.Model):
member = models.OneToOneField(Member, on_delete=models.CASCADE, related_name='is_member')
start_date = models.DateField(default=django.utils.timezone.now)
end_date = models.DateField(default=django.utils.timezone.now)
status = models.CharField(max_length=2, choices=(('1','Active'), ('2','Inactive')), default = '1', blank=True, null=True)
def __str__(self):
return str(f"{self.member}")
Согласно сообщению об ошибке. Проблема возникает после вызова form.save(). Самое странное, что код отлично работает, пока вы не добавляете новых членов и не обновляете/удаляете, затем через некоторое время он ломается. Я подозреваю, что функция обновления неправильно передает ID. Возможно, я получаю ActiveMember ID, а не Member ID? Или это не имеет значения. Является ли Django достаточно умным, чтобы связать эти две функции? views.py update method
@login_required(login_url='authenticate/admin_login')
def update(request, id):
member = ActiveMember.objects.get(pk=id)
if request.method == 'POST':
form = ActiveMemberForm(request.POST, instance=member)
if form.is_valid():
# save form data to variables
member = form.cleaned_data['member']
start_date = form.cleaned_data['start_date']
status = form.cleaned_data['status']
# send WhatsApp message to inform user his membership has been activated.
if member.phone is not None and status == '1':
msg = WhatsApp(member.full_name, member.phone, start_date)
msg.send_message('customer_active')
# save form to database.
form.save()
# redirect to the success message
return render(request, 'members/update.html', {
'form': form,
'success': True,
})
else:
form = ActiveMemberForm(instance=member)
return render(request, 'members/update.html', {
'form': form,
'member': member,
})
по запросу файл forms.py
class MemberForm(ModelForm):
def __init__(self, *args, **kwargs):
super(MemberForm, self).__init__(*args, **kwargs)
self.fields['image'].required = False
self.fields['email'].required = False
self.fields['date_created'].disabled = True
class Meta:
model = Member
fields = (
'full_name',
'email',
'phone',
'image',
'detail',
'date_created',
)
class ActiveMemberForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ActiveMemberForm, self).__init__(*args, **kwargs)
pass
class Meta:
model = ActiveMember
fields = (
'member',
'start_date',
'end_date',
'status',
)
widgets = {
'start_date': widgets.DateInput(attrs={'type': 'date'}),
'end_date': widgets.DateInput(attrs={'type': 'date'}),
}
def clean(self):
start_date = self.cleaned_data['start_date']
end_date = self.cleaned_data['end_date']
if start_date < timezone.now().date():
raise ValidationError('Please enter a valid start date!')
if end_date < timezone.now().date() or end_date < start_date:
raise ValidationError('Please enter a valid end date!')
return self.cleaned_data
В начале функции обновления представления вы присваиваете локальной member
переменной ActiveMember
экземпляр:
member = ActiveMember.objects.get(pk=id)
Затем вы передаете member
в конструктор формы. Позже в коде вы присваиваете ActiveMember.member
переменной member
, которая сама является экземпляром Member
:
member = form.cleaned_data['member']
Просто попытка в темноте, но там могут быть подкручены идентификаторы. Тем не менее, вы всегда должны санировать SomeModel.objects.get(pk)
с блоком try except, как показано в документации . Это защитит вас от ошибок.