I get this error message. I am not sure why? It says it's coming after saving my form from the update function in my views.py file.
Integraty Error:
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
Environment:
Request Method: POST
Request URL: https://topxgym.pythonanywhere.com/update/8
Django Version: 4.1
Python Version: 3.9.5
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'members',
'authenticate']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/sqlite3/base.py", line 357, in execute
return Database.Cursor.execute(self, query, params)
The above exception (UNIQUE constraint failed: members_activemember.member_id) was the direct cause of the following exception:
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/home/topxgym/.virtualenvs/env/topxgym/members/views.py", line 196, in update
form.save()
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/forms/models.py", line 548, in save
self.instance.save()
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/base.py", line 831, in save
self.save_base(
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/base.py", line 882, in save_base
updated = self._save_table(
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/base.py", line 995, in _save_table
updated = self._do_update(
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/base.py", line 1059, in _do_update
return filtered._update(values) > 0
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/query.py", line 1215, in _update
return query.get_compiler(self.db).execute_sql(CURSOR)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1819, in execute_sql
cursor = super().execute_sql(result_type)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1395, in execute_sql
cursor.execute(sql, params)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/utils.py", line 103, in execute
return super().execute(sql, params)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/home/topxgym/.virtualenvs/env/lib/python3.9/site-packages/django/db/backends/sqlite3/base.py", line 357, in execute
return Database.Cursor.execute(self, query, params)
Exception Type: IntegrityError at /update/8
Exception Value: UNIQUE constraint failed: members_activemember.member_id
These are my two models Member and ActiveMember. It uses a OneToOneField because a member can only have one membership, activation date, end date and status. But I suspect the Unique error is coming because of the OneToOneField because the update is mixing the ID's maybe? and A member is being assigned multiple memberships? That's my best guess. 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}")
According the the error message. The problem is happening after the form.save() is being called. The weird part the code works perfectly until you keep adding new members and updating/deleting then after a while it breaks. The update function isn't passing the ID correctly I suspect. I might be getting ActiveMember ID not Member ID? or that doesn't matter. Is Django smart enough to link the two? 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,
})
as requested the forms.py file
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
Management/Commands/active.py script
class Command(BaseCommand):
help = 'Deactivate expired memberships!'
def handle(self, *args, **options):
# Activate membership based on start_date
ActiveMember.objects.filter(start_date=datetime.now().date()).update(status='1')
# Deactivate membership based on end_date
ActiveMember.objects.filter(end_date=datetime.now().date()).update(status='2')
# Send WhatsApp message to active members
active_members = ActiveMember.objects.filter(start_date=datetime.now().date())
send_membership_status(active_members, 'customer_active')
# Send WhatsApp message to expired members
expired_members = ActiveMember.objects.filter(end_date=datetime.now().date())
send_membership_status(expired_members, 'customer_expire')
def send_membership_status(memberships, template_name):
for membership in memberships:
name = membership.member.full_name
phone = membership.member.phone
if template_name == 'customer_expire':
date = membership.end_date
else:
date = membership.start_date
if phone is not None:
msg = WhatsApp(name, phone, date)
msg.send_message(template_name)
CodePudding user response:
At the beginning of the update view function you are assigning the local member
variable an ActiveMember
instance:
member = ActiveMember.objects.get(pk=id)
You then pass member
into the form constructor. Later in the code you assign ActiveMember.member
to the member
variable, which itself is a Member
instance:
member = form.cleaned_data['member']
Just a shot in the dark but ids could be twisted there. Still you should always sanitize SomeModel.objects.get(pk)
with a try except block like shown in the documentation. This will protect you from errors.