duplicate key value violates unique constraint itemstaticlabel_item_id_f9405967_uniq - django

I know, this problem happens because the code is trying to add an entry to the database with a combination of unique keys that already exist. But my question is: why and how can I prevent this? It doesn't make sense to me that this is happening, given my logic.
I have this piece of code that basically stores some static label for an invoice. The idea is to create the label on the fly if it doesn't exist, instead of manually inserting it in a lot of places in the code.
Whenever an Item is generated, an ItemInv is also created, and by saving the latter, I check if a static label exists. If it doesn't, a new one is created. The code to get (or create) the static label is also called when displaying an Invoice / Draft.
The error seems to happen right there. The label doesn't exist, a new one is created, but somehow this happens twice? I mean, I really don't get why that code would try to add the same item two times. Could it be a thread issue?
I am not using get_or_create because some attributes on ItemStaticInv (static_account_label, static_agreement_label...) can be updated and not unique. Before creating the invoice, a draft has the same structure and the data can be changed, including these labels.
class ItemInv(managers.Model):
"""
Relation between Item and Invoice
"""
item = models.ForeignKey('Item')
invoice = models.ForeignKey('Invoice')
[...]
class Meta:
unique_together = ('item', 'invoice')
def save(self, *args, **kwargs):
iteminv = super(ItemInv, self).save(*args, **kwargs)
# If the item does not have the static information, one should be created
self.item.get_invoice_static(self.invoice)
return iteminv
class Item(managers.Model):
"""
Item to be put on an invoice
"""
serial = models.AutoField(primary_key=True) # Software license
product = models.ForeignKey('Product', verbose_name='Product')
account = models.ForeignKey('Account', verbose_name='Account', related_name='items')
[...]
def get_invoice_static(self, document):
try:
return self.document_labels.get(invoice=document)
except ObjectDoesNotExist:
return ItemStaticLabel.objects.create(
item=self,
invoice=document,
static_account_label=str(self.account),
static_customer_label=str(self.account.customer),
static_agreement_label=str(self.account.agreement)
)
class ItemStaticLabel(managers.Model):
"""
We must store static information about the Item on an invoice.
"""
item = models.ForeignKey('Item', related_name='document_labels')
invoice = models.ForeignKey('Invoice', related_name='item_labels')
static_account_label = models.CharField(max_length=256, null=True, blank=True)
static_customer_label = models.CharField(max_length=256, null=True, blank=True)
static_agreement_label = models.CharField(max_length=256, null=True, blank=True)
static_expiration_label = models.DateField(max_length=256, null=True, blank=True)
class Meta:
unique_together = ('item', 'invoice')
This has several flaws, but this system was developed by someone else and is on production. The amount of structural changes I can do are pretty much limited. Therefore I gotta try to understand what is causing this issue.
Traceback:
File "/home/apps/sites/invoice/source/v3/models.py" in get_invoice_static
1105. return self.document_labels.get(invoice=document)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/manager.py" in manager_method
85. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/query.py" in get
380. self.model._meta.object_name
During handling of the above exception (ItemStaticLabel matching query does not exist.), another exception occurred:
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
The above exception (duplicate key value violates unique constraint "v3_itemstaticlabel_item_id_f9405967_uniq"
DETAIL: Key (item_id, invoice_id)=(1840, 1578) already exists.
) was the direct cause of the following exception:
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/base.py" in _legacy_get_response
249. response = self._get_response(request)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.4/contextlib.py" in inner
30. return func(*args, **kwds)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/views/generic/base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/views/generic/detail.py" in get
116. context = self.get_context_data(object=self.object)
File "/home/apps/sites/invoice/source/web/views/invoice.py" in get_context_data
280. context['document_html'] = services.document_to_html(obj)
File "/home/apps/sites/invoice/source/v3/services.py" in document_to_html
1550. 'account': set_[0].get_invoice_static(document).static_account_label,
File "/home/apps/sites/invoice/source/v3/models.py" in get_invoice_static
1112. static_agreement_label=str(self.account.agreement)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/manager.py" in manager_method
85. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/query.py" in create
394. obj.save(force_insert=True, using=self.db)
File "/home/apps/sites/invoice/source/v3/managers.py" in save
724. super().save(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in save
808. force_update=force_update, update_fields=update_fields)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in save_base
838. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in _save_table
924. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in _do_insert
963. using=using, raw=raw)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/manager.py" in manager_method
85. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/query.py" in _insert
1076. return query.get_compiler(using=using).execute_sql(return_id)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/sql/compiler.py" in execute_sql
1107. cursor.execute(sql, params)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/utils.py" in __exit__
94. six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/utils/six.py" in reraise
685. raise value.with_traceback(tb)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
Exception Type: IntegrityError at /invoice-menu/customer/251/invoices/1578/
Exception Value: duplicate key value violates unique constraint "v3_itemstaticlabel_item_id_f9405967_uniq"
DETAIL: Key (item_id, invoice_id)=(1840, 1578) already exists.
View
class InvoiceDetailView(DetailView):
model = Invoice
template_name = 'invoice_detail.html'
pk_url_kwarg = 'invoice_key'
context_object_name = 'invoice'
def get_context_data(self, **kwargs):
context = super(InvoiceDetailView, self).get_context_data(**kwargs)
obj = context[self.context_object_name]
obj = models.Invoice.objects.filter(pk=obj.pk).select_related(
'customer',
'customer__original',
'currency',
).prefetch_related(
'citems',
'citems__assocs',
'citems__assocs__product',
'iteminv_set',
'iteminv_set__item',
).first()
context['document_html'] = services.document_to_html(obj)
return context
Services
def document_to_html(document):
"""
Renders the invoice to html.
"""
from v3.models import Item, Maintenance, Invoice, CustomInvoiceLine
from web.collection_utils import collapse_list
data = {}
items = Item.objects.on_invoice(document)
mains = Maintenance.objects.on_invoice(document)
rows = get_invoice_product_rows(document)
# merge the lists
rows['itemrows'].extend(rows['mainrows'])
include_summary = len(rows['itemrows']) > 0 and not Invoice.objects.filter(creditted_by=document)
# calc VAT lines
vats = {}
for ir in rows['itemrows']:
row = ir['line']
vat = ir['objs'][0].vat
rate = ir['objs'][0].vat_rate
total = (Decimal(rate / 100) * ir['rowtotal']).quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
try:
vats[vat]['rownums'].append(row)
vats[vat]['total'] += total
except:
vats[vat] = dict(rownums=[row, ], message=ir['objs'][0].vat_message, total=total, rate=rate)
for mr in rows['mainrows']:
row = mr['line']
vat = mr['objs'][0].vat
rate = mr['objs'][0].vat_rate
total = (Decimal(rate / 100) * mr['rowtotal']).quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
try:
vats[vat]['rownums'].append(row)
# Changed it to not add any value because that will produce wrong vat output.
vats[vat]['total'] += 0
except:
vats[vat] = dict(rownums=[row, ], message=mr['objs'][0].vat_message, total=total, rate=rate)
for cr in rows['citemrows']:
row = cr['line']
vat = cr['obj'].vat
rate = cr['obj'].vat_rate
total = (Decimal(rate / 100) * cr['rowtotal']).quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
try:
vats[vat]['rownums'].append(row)
vats[vat]['total'] += total
except:
vats[vat] = [row, ]
vats[vat] = dict(rownums=[row, ], message=cr['obj'].vat_message, total=total, rate=rate)
vats = [(k, collapse_list(v['rownums']), v['message'], v['total'], v['rate']) for (k, v) in vats.items()]
vats = sorted(vats, key=lambda x: x[1])
# Gather data for the license agreement overview
# A list of lists, where the inner lists contain items that match on product and account
matched_item_sets = []
items = list(items) + list([m.serial for m in mains])
for item in items:
# Find a set to add this item to
for set_ in matched_item_sets:
if item.product == set_[0].product and item.account == set_[0].account:
if item not in set_:
set_.append(item)
break
else:
# No matching set found. Create a new one
matched_item_sets.append([item])
# Package the item sets nicely with meta information
summary = []
for set_ in matched_item_sets:
summary.append({
'account': set_[0].get_invoice_static(document).static_account_label,
'owner': set_[0].get_invoice_static(document).static_customer_label,
'agreement': set_[0].get_invoice_static(document).static_agreement_label,
'product': set_[0].product,
'licenses': collapse_list(set_),
})
data['inv'] = document
data['lines'] = rows['itemrows']
data['citems'] = rows['citemrows']
data['vats'] = vats
data['lagree'] = summary
data['includeSummary'] = include_summary
data['cilines'] = CustomInvoiceLine.objects.filter(invoice=document, on_invoice=True)
data['base_url'] = settings.SITE_BASE_URL
tpl = document.template
tpl = DjangoTemplate(tpl.content)
return tpl.render(Context(data))

Related

Role choice field data ins't saved for UserRegsitrationForm django

The following error message appears after I submit the SignUpform:
'NoneType' object has no attribute '_inc_path'
This issue is related to the role choice field of my CustomUser model. The models function perfectly without the role field and all forms are displayed and saved correctly.
I suspect my choice field form does not pass/save correctly the input values to the CustomUser model.
Any input would be highly appreciated.
Models.py:
class CustomUser(AbstractUser):
display_name = models.CharField(verbose_name=("Display name"), max_length=30, help_text=("Will be shown e.g. when commenting"))
...
country = CountryField(blank=True, null=True)
...
role = models.CharField(choices = ROLES, max_length = 50, default = "regular_user",)
...
class Meta:
ordering = ['last_name']
def get_absolute_url(self):
return reverse('account_profile')
def __str__(self):
return f"{self.username}: {self.first_name} {self.last_name}" ```
forms.py:
class SignupForm(forms.Form):
first_name = forms.CharField(max_length=30, label=_("First name"))
last_name = forms.CharField(max_length=30, label=_("Last name"))
display_name = forms.CharField(max_length=30, label=_("Display name"), help_text=_("Will be shown e.g. when commenting."))
role = forms.ChoiceField(choices = ROLES, label="Role", initial='Regular_user', widget=forms.Select(), required=True)
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.display_name = self.cleaned_data['display_name']
user.role = self.cleaned_data['role']
user.save()
users/create.html:
{% extends "wagtailusers/users/create.html" %}
{% block extra_fields %}
...
{% include "wagtailadmin/shared/field_as_li.html" with field=form.role %}
...
{% endblock extra_fields %}
settings.py:
AUTH_USER_MODEL = 'userauth.CustomUser'
WAGTAIL_USER_CREATION_FORM ='userauth.forms.WagtailUserCreationForm'
WAGTAIL_USER_EDIT_FORM = 'userauth.forms.WagtailUserEditForm'
WAGTAIL_USER_CUSTOM_FIELDS = ['display_name',... 'role', ...]
ACCOUNT_SIGNUP_FORM_CLASS = 'userauth.forms.SignupForm'
Error log:
2022-10-17 10:16:35,894: Internal Server Error: /accounts/signup/
Traceback (most recent call last):
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/teki/.virtualenvs/bup/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/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/views/generic/base.py", line 84, in view
return self.dispatch(request, *args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/utils/decorators.py", line 46, in _wrapper
return bound_method(*args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/decorators.py", line 20, in wrap
resp = function(request, *args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/utils/decorators.py", line 46, in _wrapper
return bound_method(*args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/views/decorators/debug.py", line 92, in sensitive_post_parameters_wrapper
return view(request, *args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/account/views.py", line 234, in dispatch
return super(SignupView, self).dispatch(request, *args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/account/views.py", line 77, in dispatch
response = super(RedirectAuthenticatedUserMixin, self).dispatch(
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/account/views.py", line 207, in dispatch
return super(CloseableSignupMixin, self).dispatch(request, *args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/views/generic/base.py", line 119, in dispatch
return handler(request, *args, **kwargs)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/account/views.py", line 105, in post
response = self.form_valid(form)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/account/views.py", line 252, in form_valid
return complete_signup(
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/allauth/account/utils.py", line 183, in complete_signup
signals.user_signed_up.send(
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 176, in send
return [
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 177, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "/home/teki/fommestyuta/users/models.py", line 38, in create_user_group_and_pages
home.add_child(instance=article_index_page)
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/treebeard/mp_tree.py", line 1083, in add_child
return MP_AddChildHandler(self, **kwargs).process()
File "/home/teki/.virtualenvs/bup/lib/python3.9/site-packages/treebeard/mp_tree.py", line 377, in process
newobj.path = self.node.get_last_child()._inc_path()
AttributeError: 'NoneType' object has no attribute '_inc_path'
create_user_group_and_pages:
from django.db import models
from django.contrib.auth.models import Group, Permission
from django.dispatch import receiver
from allauth.account.signals import user_signed_up
from wagtail.core.models import Page, GroupPagePermission, GroupCollectionPermission, Collection
from cms.models import ArticleIndexPage
#receiver(user_signed_up)
def create_user_group_and_pages(sender, **kwargs):
"""
When a new user signs up create a unique group and page for them.
Assign it the appropriate permission for admin, page and collection access.
"""
# Grab the new user
user = kwargs['user']
# Create a group object that matches their username
new_group, created = Group.objects.get_or_create(name=user.username)
# Add the new group to the database
user.groups.add(new_group)
# Create new permission to access the wagtail admin
access_admin = Permission.objects.get(codename='access_admin')
# Add the permission to the group
new_group.permissions.add(access_admin)
# Now start creating page access
# First find the homepage
home = Page.objects.get(slug='home').specific
# Create unique PersonIndexPage for the user
article_index_page = ArticleIndexPage(title=user.username)
# Add PersonIndexPage to homepage as a child
home.add_child(instance=article_index_page)
# Save new page as first revision
article_index_page.save_revision()
# Create new add GroupPagePermission
GroupPagePermission.objects.create(
group=new_group,
page=article_index_page,
permission_type='add'
)
# Create new GroupCollectionPermission for Profile Images collection
GroupCollectionPermission.objects.create(
group=new_group,
collection=Collection.objects.get(name='Images'),
permission=Permission.objects.get(codename='add_image')
)
It looks like the page tree data in your database has become inconsistent, causing it to fail when creating the new ArticleIndexPage. (Specifically, the record for the 'home' page shows that it has existing child pages, meaning that it has to look at those child page records to find the correct position for the new page - but when it tries retrieving those child pages, none are being returned.) This may have happened due to a previous error occurring part-way through creating or deleting a page.
To fix this, run: ./manage.py fixtree

Django - Are all relevent models needed when testing the URL of a functional view?

I have several functional views that are passed parameters. I'm trying to write tests to check the url, status, etc. So far I'm starting with just testing the URL name. I have some querysets in the view and it looks from the traceback that I need to define objects for the queries in my setUp
urls
app_name = 'gradebook'
urlpatterns = [
path('updatesinglegrade/<int:assess_pk>/<int:class_pk>/<int:grade_pk>/',
views.updatesinglegrade, name='updatesinglegrade'),
]
view
def updatesinglegrade(request, assess_pk, class_pk, grade_pk):
grade = Grade.objects.get(id=grade_pk)
gradescale = GradeBookSetup.objects.get(user=request.user)
scale_choice = grade_scale_choice(gradescale.scale_mode)
form = UpdateGradeForm(gradescale=scale_choice)
context = {'form': form}
context['grade'] = grade
if request.method == 'POST':
form = UpdateGradeForm(
request.POST, gradescale=scale_choice)
if form.is_valid():
cd = form.cleaned_data
grade.score = cd['score']
grade.save()
return redirect('gradebook:assessdetail', assess_pk, class_pk)
else:
return render(request, "gradebook/grade_single_form.html", context)
else:
return render(request, "gradebook/grade_single_form.html", context)
test
class UpdateSingleGradeTests(TestCase):
def setUp(self):
self.user = CustomUser.objects.create_user(
username='tester',
email='tester#email.com',
password='tester123'
)
login = self.client.login(username='tester', password='tester123')
def test_updatesinglegrade_url_name(self):
response = self.client.get(reverse('gradebook:updatesinglegrade', kwargs={
'assess_pk': 1, 'class_pk': 2, 'grade_pk': 3}))
self.assertEqual(response.status_code, 200)
traceback
======================================================================
ERROR: test_updatesinglegrade_url_name (gradebook.tests.UpdateSingleGradeTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\Doug\OneDrive\django\gradebook\gradebook\tests.py", line 102, in test_updatesinglegrade_url_name
response = self.client.get(reverse('gradebook:updatesinglegrade', kwargs={
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\test\client.py", line 742, in get
response = super().get(path, data=data, secure=secure, **extra)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\test\client.py", line 396, in get
return self.generic('GET', path, secure=secure, **{
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\test\client.py", line 473, in generic
return self.request(**r)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\test\client.py", line 719, in request
self.check_exception(response)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\test\client.py", line 580, in check_exception
raise exc_value
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "C:\Users\Doug\OneDrive\django\gradebook\gradebook\views.py", line 1030, in updatesinglegrade
grade = Grade.objects.get(id=grade_pk)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Doug\.virtualenvs\gradebook-6RQSg7dk\lib\site-packages\django\db\models\query.py", line 435, in get
raise self.model.DoesNotExist(
gradebook.models.Grade.DoesNotExist: Grade matching query does not exist.
----------------------------------------------------------------------
Ran 6 tests in 1.527s
FAILED (errors=1)
I can create a Grade object as the traceback indicates, but my Grade model depends on five ForeignKeys, one of which has another ForeignKey:
model
class Grade(models.Model):
score = models.CharField(max_length=3, blank=True, default="INC")
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
assessment = models.ForeignKey(
Assessment, on_delete=models.CASCADE, null=True, blank=True)
objective = models.ForeignKey(
Objective, on_delete=models.CASCADE, blank=True)
student = models.ForeignKey(Student, on_delete=models.CASCADE)
cblock = models.ForeignKey(Classroom, on_delete=models.CASCADE, default=1)
time_created = models.DateField(
auto_now=False, auto_now_add=False, default=timezone.now)
working test
from .models import CustomUser, Grade, Student, Course, Classroom, Objective, Assessment, GradeBookSetup
class UpdateSingleGradeTests(TestCase):
def setUp(self):
self.user = CustomUser.objects.create_user(
username='tester',
email='tester#email.com',
password='tester123',
is_teacher=True,
)
studentuser = CustomUser.objects.create(
username='student_test'
)
stud = Student.objects.create(
user=studentuser,
student_number='111222'
)
course = Course.objects.create(
user=self.user
)
classroom = Classroom.objects.create(
user=self.user,
course=course
)
# classroom.students.set(stud)
objective = Objective.objects.create(
user=self.user,
course=course
)
assessment = Assessment.objects.create(
user=self.user,
course=course
)
# assessment.objectives.set(objective)
login = self.client.login(username='tester', password='tester123')
grade = Grade.objects.create(
id=3,
user=self.user,
student=stud,
objective=objective,
cblock=classroom,
assessment=assessment
)
gbs = GradeBookSetup.objects.create(
id=1,
user=self.user
)
def test_updatesinglegrade_url_name(self):
response = self.client.get(reverse('gradebook:updatesinglegrade', kwargs={
'assess_pk': 1, 'class_pk': 2, 'grade_pk': 3}))
self.assertEqual(response.status_code, 200)
Does this mean that I need to create 6 objects in the setUp? I got it work for this test, and I'm wondering if this is something I will have to add to many of my class TestCase (which have similar objects/models involved)? Or perhaps there is a more efficient way of doing this?
The short answer is, yes, non-null ForeignKey fields must be populated in tests because they are non-null.
There are several ways to do this:
Call objects.create() on each model. This can be very tedious and time consuming.
Use a fixture. Creating the JSON files can also be tedious, but fortunately, you can use the Django admin to do data entry and then ./manage.py dumpdata to generate the JSON.
Use a 3rd party library such as factory-boy or model-bakery. These libraries can generate random data for fields that don't really matter for testing other than that they have a value. If you need a specific value for a certain test, then you can provide it.
You can create fixture and use it in your TestCase class
docs on subject: https://docs.djangoproject.com/en/3.2/topics/testing/tools/#fixture-loading
class UpdateSingleGradeTests(TestCase):
fixtures = ['fixture.json']

ValueError - The annotation 'status' conflicts with a field on the model django

I'm trying to perform a bit of complicated query in my rest api view so I can order my contacts in the right order, now as e4c5 suggested in my previous question I could do this Case annotation and build my custom annotation with CASE/WHEN and then use that in annotation in the order by, but now I'm getting ValueError at /api/sales/lead_contact/
The annotation 'status' conflicts with a field on the model so this is the custom annotation I'm trying to build so I can properly order contacts, one note is that I'm preforming this in rest view:
class LeadContactViewSet(viewsets.ModelViewSet):
def get_queryset(self):
filter_date = self.request.query_params.get('filter_date', None)
case_sql = LeadContact.objects.annotate(
status=Case(
When(status=LeadContactConstants.STATUS_CLIENT, then=Value('1')),
When(status=LeadContactConstants.STATUS_QUALIFIED, then=Value('2')),
When(status=LeadContactConstants.STATUS_CONTACTED, then=Value('3')),
When(status=LeadContactConstants.STATUS_PRISTINE, then=Value('4')),
default=Value('1'),
output_field=CharField(),
)
).values_list('status')
if filter_date is not None:
queryset = queryset.filter(next_action_date=filter_date).extra(select={'status': case_sql},
order_by=['status'])
return queryset
Model fields:
class LeadContact(models.Model):
status = models.CharField(max_length=10,
choices=LeadContactConstants.STATUSES, default=LeadContactConstants.STATUS_PRISTINE)
and the choices for this field:
class LeadContactConstants(object):
STATUS_PRISTINE = "PRISTINE"
STATUS_CONTACTED = "CONTACTED"
STATUS_QUALIFIED = "QUALIFIED"
STATUS_CLIENT = "CLIENT"
STATUSES = ((STATUS_PRISTINE, "Virgin"),
(STATUS_CONTACTED, "Contacted"),
(STATUS_QUALIFIED, "Qualified"),
(STATUS_CLIENT, "Client"))
Serializer class:
class LeadContactSerializer(serializers.ModelSerializer):
account_handler = AccountHandlerSerializer()
next_action_date = serializers.DateTimeField(format=settings.CUSTOM_DATE_FORMAT_NO_TIME)
absolute_url = serializers.URLField(source='get_absolute_url')
class Meta:
model = LeadContact
fields = (
'pk', 'organization_name', 'sub_organization_name', 'serial_number', 'account_handler', 'status_text',
'first_name', 'last_name', 'next_action_date', 'absolute_url', 'status_display_class'
)
depth = 1
Full Stack Trace:
Traceback:
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
58. return view_func(*args, **kwargs)
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view
87. return self.dispatch(request, *args, **kwargs)
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
466. response = self.handle_exception(exc)
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch
463. response = handler(request, *args, **kwargs)
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list
40. queryset = self.filter_queryset(self.get_queryset())
File "/home/vagrant/vincluos/VincluCMSProject/vinclucms_sales/restapi/views/lead_contact_viewset.py" in get_queryset
29. output_field=CharField(),
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/django/db/models/manager.py" in manager_method
127. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/vagrant/virtualenv/local/lib/python2.7/site-packages/django/db/models/query.py" in annotate
793. "the model." % alias)
Exception Type: ValueError at /api/sales/lead_contact/
Exception Value: The annotation 'status' conflicts with a field on the model.
As you can read the error message "'status' conflicts with a field on the model",
here the error is telling you that LeadContact model already has a field status (you can see it on your model definition of LeadContact)
that's why you're not able to annotate.
Basically annotate tries to add a field to your queryset result in your case it is status as you have a model LeadContact with status field because of which you're not able to annotate.
The Solution is you have to the field name other then status and choices.
hope this helps.

MultiValueDictKeyError when editing inline admin object

I am designing a simple MCQ application using the ManyToOne relationship from django website, django version 1.6.1. I have an inline admin form which supposedly allows me to add / edit answers to a given question from the same changeform. However, if after saving a question with its answers once, i am unable to edit / add answers from the same form and get a MultiValueDictKeyError. My models are:
class SBA (models.Model):
question = models.TextField(blank=False)
system = models.CharField(max_length=3, choices=pacscon.System.which_system)
case = models.ForeignKey('pacscon.Patient')
created = models.DateField(auto_now_add=True)
reference = models.TextField(blank=True)
def __unicode__(self):
return self.question
class Answer(models.Model):
id = models.AutoField(primary_key=True)
body = models.TextField()
correct = models.BooleanField(default=False)
sba = models.ForeignKey(SBA, null=True)
def __unicode__(self):
return self.body
the admin.py looks like this :
from models import Answer, SBA, Mnemonic
#from django import forms
from django.contrib import admin
class AnswerInline(admin.StackedInline):
model = Answer
extra = 2
class SBAAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('question', 'system', 'case', 'reference')
}),
)
inlines = [
AnswerInline,
]
readonly_fields = ('created',)
admin.site.register(SBA, SBAAdmin)
admin.site.register(Answer)
admin.site.register(Mnemonic)
And the error message is :
MultiValueDictKeyError at /admin/knowledge/sba/1/
Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
114. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in wrapper
432. return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
99. response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func
52. response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py" in inner
198. return view(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapper
29. return bound_func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in _wrapped_view
99. response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py" in bound_func
25. return func(self, *args2, **kwargs2)
File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py" in inner
339. return func(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py" in change_view
1229. if all_valid(formsets) and form_validated:
File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py" in all_valid
415. if not formset.is_valid():
File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py" in is_valid
292. err = self.errors
File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py" in errors
267. self.full_clean()
File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py" in full_clean
314. form = self.forms[i]
File "/usr/local/lib/python2.7/dist-packages/django/utils/functional.py" in __get__
49. res = instance.__dict__[self.func.__name__] = self.func(instance)
File "/usr/local/lib/python2.7/dist-packages/django/forms/formsets.py" in forms
133. forms = [self._construct_form(i) for i in xrange(self.total_form_count())]
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in _construct_form
848. form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/forms/models.py" in _construct_form
564. pk = self.data[pk_key]
File "/usr/local/lib/python2.7/dist-packages/django/utils/datastructures.py" in __getitem__
301. raise MultiValueDictKeyError(repr(key))
Exception Type: MultiValueDictKeyError at /admin/knowledge/sba/1/
Exception Value: "u'answer_set-0-id'"
I have searched similar requests on google and stackoverflow and my django package is fully upto date (including admin inline templates as suggested in some other answers). Will appreciate any help. Thanks
P.S This is almost certainly a bug because I can replicate the problem on official django "Polls" tutorial which uses a similar ManyToOne relationship model.
In Django <= 1.7.3, I needed to change the primary key field of my model to AutoField:
wrong:
class Answer(models.Model):
id = IntegerField(primary_key=True)
correct:
class Answer(models.Model):
id = AutoField(primary_key=True)
See
https://code.djangoproject.com/ticket/15665
I have similar issue which was solved by update django-grappelli. If you did not use it, check your packages maybe you find what can affect work of admin site.
pip freeze | grep django- will show you current packages with versions
This answer https://stackoverflow.com/a/20246225/554807 has the explanation.
The best fix is actually to get silverfix's branch of nested-inlines: https://github.com/silverfix/django-nested-inlines
This has the fix mentioned in that answer, and others.
After migrating an application from Django==1.4.20 to Django==1.8.3 i had an outdated templates_django/admin/edit_inline/stacked.html and templates_django/admin/edit_inline/tabular.html files.
So i have just removed them and everything works fine now.
You can also upgrade them to your current django version instead of deleting.

Filter Django Queryset: ValueError

After using HttpResponseRedirect and reverse to redirect to another view, I am getting a ValueError. This is the view that processes a posted form (the form uses a ModelChoiceField to get a dropdown set of options from my Make model:
def browse(request):
thing_list = Thing.objects.all()
if request.method == 'POST':
form = BrowseForm(request.POST)
if form.is_valid():
make = form.cleaned_data['make']
return HttpResponseRedirect(reverse('browse_makes', kwargs={'make':make}))
else:
form = BrowseForm()
return render(request, 'browse.html', {'form':form, 'thing_list':thing_list})
.. then redirects to next view adding make as a kwarg to use to filter the next queryset:
def makes(request, make):
thing_list = Thing.objects.filter(make=make)
return render(request, 'browse-makes.html', {'thing_list':thing_list})
urls:
url(r'^browse/$', 'myapp.views.browse.browse', name='browse'),
url(r'^browse/(?P<make>[\w-]+)/$', 'myapp.views.browse.makes', name='browse_makes'),
Results in ValueError: invalid literal for int() with base 10: 'Samsung' when selecting an option from the form. After googling, still not sure how to solve this.. Thanks for any ideas how to solve this error!
EDIT:
abbreviated model:
class Thing(models.Model):
user = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
slug = models.SlugField()
make = models.ForeignKey(Make)
Traceback:
Traceback: File "/lib/python2.7/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs) File "/myproject/myapp/views/browse.py" in makes
21. thing_list = Thing.objects.filter(make=make) File "/lib/python2.7/django/db/models/manager.py" in filter
143. return self.get_query_set().filter(*args, **kwargs) File "/lib/python2.7/django/db/models/query.py" in filter
624. return self._filter_or_exclude(False, *args, **kwargs) File "/lib/python2.7/django/db/models/query.py" in _filter_or_exclude
642. clone.query.add_q(Q(*args, **kwargs)) File "/lib/python2.7/django/db/models/sql/query.py" in add_q
1250. can_reuse=used_aliases, force_having=force_having) File "/lib/python2.7/django/db/models/sql/query.py" in add_filter
1185. connector) File "/lib/python2.7/django/db/models/sql/where.py" in add
69. value = obj.prepare(lookup_type, value) File "/lib/python2.7/django/db/models/sql/where.py" in prepare
320. return self.field.get_prep_lookup(lookup_type, value) File "/lib/python2.7/django/db/models/fields/related.py" in get_prep_lookup
137. return self._pk_trace(value, 'get_prep_lookup', lookup_type) File "/lib/python2.7/django/db/models/fields/related.py" in _pk_trace
210. v = getattr(field, prep_func)(lookup_type, v, **kwargs) File "/lib/python2.7/django/db/models/fields/__init__.py" in get_prep_lookup
310. return self.get_prep_value(value) File "/lib/python2.7/django/db/models/fields/__init__.py" in get_prep_value
537. return int(value)
Exception Type: ValueError at /browse/Samsung/ Exception Value: invalid literal for int() with base 10: 'Samsung'
If you post your Make model, I can give a complete answer. But in general you are referencing the make foreign key directly - which is an int (the Make ID). You are comparing this int to the string 'samsung' at make=make causing the error.
Depending on what string fields your Make model has, you need to reference one of those fields. For instance, if Make had a name field that accepted strings:
thing_list = Thing.objects.filter(make__name=make)
Otherwise, you need to pass the make ID instead of 'samsung'