Django form test only fails when breakpoint set on form.is_valid() in PyCharm

20 views
Skip to first unread message

william...@gmail.com

unread,
Dec 26, 2018, 7:29:11 AM12/26/18
to Django users
I have a model called Table:

class Table(models.Model):
"""
Models tables which are initially scanned by customers. Orders are linked to tables
"""
MINIMUM_QR_WIDTH, MINIMUM_QR_HEIGHT = 115, 115
MAX_QR_SIZE = 10485760 # 10MB

number = models.CharField(max_length=256, blank=False, null=False)

identifier = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
venue = models.ForeignKey(Venue, null=False, blank=False, on_delete=models.CASCADE)
qr_code = models.ImageField(upload_to='table_qr_codes', blank=True, null=True)

def __str__(self):
return "Table " + self.number

class Meta:
unique_together = ('venue', 'number')
ordering = ['venue', 'number']


I have a ModelForm to create Table objects called TableAddForm.

class TableAddForm(forms.ModelForm):

class Meta:
model = Table
fields = ['number', 'qr_code', 'venue']

def clean_qr_code(self):
qr = self.cleaned_data.get('qr_code')

if qr:
w, h = get_image_dimensions(qr)
if w < Table.MINIMUM_QR_WIDTH or h < Table.MINIMUM_QR_HEIGHT:
msg = forms.ValidationError("The image you selected is too small. QR codes must be at least " + str(Table.MINIMUM_QR_WIDTH)
+ "px by " + str(Table.MINIMUM_QR_HEIGHT) + "px.")
self.add_error('qr_code', msg)

if qr.size > Table.MAX_QR_SIZE:
msg = forms.ValidationError("The file you uploaded is too large. File size can be up to " + str(size(Table.MAX_QR_SIZE))
+ ". File size is currently " + str(size(qr.size)))
self.add_error('logo', msg)

return qr

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['venue'].empty_label = 'Select your venue'

I have a test for the TableAddForm.

class TableAddFormTests(TestCase):
def setUp(self):
user = User.objects.create(username='jo...@email.com', password='password', email='jo...@email.com')
business1 = create_business(name='business1', owner=user)
venue = create_venue(name='venue1', address='address1', zip='zip1', city='city1', country='country1', business=business1)

def test_valid_data(self):
qr = SimpleUploadedFile(name='valid_qr.png', content=open('media/tests/225_by_225_image.png', 'rb').read())
venue = get_object_or_404(Venue, name='venue1')
data = {'number': 1, 'venue': venue.pk}
form = TableAddForm(data=data, files={'qr_code': qr})
self.assertTrue(form.is_valid())
table = form.save()
self.assertEqual(table.number, '1')
self.assertEqual(table.venue, venue)
self.assertEqual(open('media/tests/225_by_225_image.png', 'rb').read(), table.qr_code.read())


When I run test_valid_data() without breakpoints in PyCharm, it passes. When I run the test with a break point on: "self.assertTrue(form.is_valid()) two things happen.

1. The breakpoints on Django's_clean_fields() method are ignored (i.e. code execution is not stopped at the breakpoints).

2. The venue key is not present in the form’s cleaned_data dictionary (as can be seen in the screenshot below). This leads to an integrity error when I try to save the form as Table objects must

have a Venue foreign key.


Screenshot 2018-12-26 at 15.13.11.jpg


















Fig 1. Screenshot of debugger variables just before I call form.save() if I have set a breakpoint on form.is_valid()

Traceback when I attempt to save the form without a Venue in cleaned_data.

Error Traceback (most recent call last): File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 296, in execute return Database.Cursor.execute(self, query, params) sqlite3.IntegrityError: NOT NULL constraint failed: sk_business_table.venue_id The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/Users/williamdavies/Documents/PyCharmProjects/SwiftKiosk_new/swiftkiosk/sk_business/test_forms.py", line 322, in test_valid_data table = form.save() File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/forms/models.py", line 458, in save self.instance.save() File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/base.py", line 717, in save force_update=force_update, update_fields=update_fields) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/base.py", line 747, in save_base updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/base.py", line 830, in _save_table result = self._do_insert(cls._base_manager, using, fields, update_pk, raw) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/base.py", line 868, in _do_insert using=using, raw=raw) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/query.py", line 1133, in _insert return query.get_compiler(using=using).execute_sql(return_id) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1285, in execute_sql cursor.execute(sql, params) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute return self._execute_with_wrappers(sql, params, many=False, executor=self._execute) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers return executor(sql, params, many, context) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "/Users/williamdavies/.virtualenvs/swiftkiosknew/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 296, in execute return Database.Cursor.execute(self, query, params) django.db.utils.IntegrityError: NOT NULL constraint failed: sk_business_table.venue_id Destroying test database for alias 'default'... Process finished with exit code 1

When I run the test with a breakpoint on any other line, the problem is not reproduced and the breakpoints in Django’s _clean_fields() method are called. It seems that setting a breakpoint on the line where

I call form.is_valid() changes the way the form data is cleaned and the venue foreign key is not processed correctly, leading to its absence in cleaned_data.


Thanks for reading through this and any help would really be appreciated! If you need any other code/tracebacks/screenshots etc that I missed please let me know and I’d be happy to provide!


Will




Reply all
Reply to author
Forward
0 new messages