Django and nosetests : DoesNotExist: <object> matching query does not exist - django

I'm just starting a small app on django. Its aim, for now, is just to manage testers (aka users) and teams. here's my model.py :
from django.db import models
class Team(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
def get_testers(self):
return self.tester_set.all()
class Tester(models.Model):
team = models.ForeignKey(Team)
visa = models.CharField(max_length=3)
privileged = models.BooleanField()
def __unicode__(self):
return self.visa
I'm trying to write a test for the "get_testers" function.
Here it is :
from models import Team, Tester
def testTeamGetTesters_test():
t = list(Team.objects.get(id=2L).get_testers())
a = Tester(visa = 'a', privileged = True)
b = Tester(visa = 'b', privileged = True)
assert(t[0].visa == a.visa and t[0].privileged == a.privileged and t[1].visa == b.visa and t[1].privileged == b.privileged)
But when I run :
$ python manage.py test tmg
I get this error :
nosetests --verbosity 1 tmg
E
======================================================================
ERROR: tempsite.tmg.tests.testTeamGetTesters_test
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.6/nose/case.py", line 183, in runTest
self.test(*self.arg)
File "/home/charlie/code/tempsite/../tempsite/tmg/tests.py", line 8, in testTeamGetTesters_test
t = list(Team.objects.get(id=2L).get_testers())
File "/usr/lib/pymodules/python2.6/django/db/models/manager.py", line 132, in get
return self.get_query_set().get(*args, **kwargs)
File "/usr/lib/pymodules/python2.6/django/db/models/query.py", line 341, in get
% self.model._meta.object_name)
DoesNotExist: Team matching query does not exist.
So, I wrote just about the same test, but directly runable :
from models import Team, Tester
t = list(Team.objects.get(id=2L).get_testers())
a = Tester(visa = 'a', privileged = True)
b = Tester(visa = 'b', privileged = True)
print "%r" % (t[0].visa == a.visa and t[0].privileged == a.privileged and t[1].visa == b.visa and t[1].privileged == b.privileged)
...And when I run it :
$ python tests.py
True
This is very confusing... I checked the database, the objects are all perfectly retrieved, but I still get this error...

Are you creating the Team object with id 2 somewhere in your test? Don't forget tests start with a blank database.

Related

Select related executes queries

I can't make select_related work with the following configuration:
Models:
class Text(models.Model):
author = models.ForeignKey('authors.Author',
on_delete=models.SET_NULL,
blank=True,
null=True)
Author model:
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
kwargs = {'pk': self.pk}
return reverse('author-detail', kwargs=kwargs)
View
In a view, I use the select_related function to avoid hitting the db when querying for text's authors e.g.:mytext.author:
class TextsViewTest(TestCase):
def text_view(request,
pk,
template_name='texts/detail.html'):
source_text = Text.objects.select_related('author').get(pk=pk)
return render(request, template_name,
{
'source': source_text,
})
Test
According to select_related it shouldn't hit the database when accessing the Text.author relationship, but when testing it with:
def test_layout_content_header__uses_prefetched_relationships(self):
author = Author.objects.create(name="foobar")
source_text = Text.objects.create(author=author)
context = {'source': source_text}
with self.assertNumQueries(0):
from django.template.loader import render_to_string
rendered = render_to_string("text/_content_header.html", context)
template
text/content_header.html:
{% if source.author %} by <em>{{source.author.name}}</em>{% endif %}
Output
./manage test texts.test_views shows a hit:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_layout_content_header__uses_prefetched_relationships (author.tests.test_views.TextsViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../text/tests/test_views.py", line 1035, in test_layout_content_header__uses_prefetched_relationships
source_text.author
File "/.../lib/python3.6/site-packages/django/test/testcases.py", line 80, in __exit__
'%d. %s' % (i, query['sql']) for i, query in enumerate(self.captured_queries, start=1)
AssertionError: 1 != 0 : 1 queries executed, 0 expected
Captured queries were:
1. SELECT "authors_author"."id", "authors_author"."name", FROM "authors_author" WHERE "authors_author"."id" = 1
----------------------------------------------------------------------
Ran 1 test in 0.489s
FAILED (failures=1)
Destroying test database for alias 'default'...
Any ideas?
It looks like you are not using your view's code inside the test. Try either to copy same query into your test, e.g.:
context = {'source': Text.objects.select_related('author').get(pk=source_text.pk)}
with self.assertNumQueries(0):
from django.template.loader import render_to_string
rendered = render_to_string("text/_content_header.html", context)
Or reuse the view code (it seems to be declared in the Test Case, right?)
with self.assertNumQueries(1):
self.text_view(MagicMock(), source_text.pk)
Although you might need to specify bit more advanced request mock, e.g. using the RequestFactory

How to test clean_<fieldname> method?

I try to write a test for my clean_ method.
Here is the code for my test
def test_clean_restraints(self):
form = NewTaskForm(dict(restraints="90 20 <>"))
form.clean_restraints()
At this step I receive an error:
Error
Traceback (most recent call last):
File "/home/user/django_projects/my_webservice/tasks/tests/test_forms.py", line 12, in test_clean_restraints
form.clean_restraints()
File "/home/user/django_projects/my_webservice/tasks/forms.py", line 22, in clean_restraints
if self.cleaned_data.get('restraints') == '':
AttributeError: 'NewTaskForm' object has no attribute 'cleaned_data'
NewTaskForm looks like this:
class NewTaskForm(ModelForm):
class Meta:
model = Task
restraints = forms.CharField()
region = forms.CharField()
interactions = forms.CharField()
def clean_restraints(self):
if self.cleaned_data.get('restraints') == '':
return self.cleaned_data.get('restraints')
data = self.cleaned_data.get('restraints').strip().split('\n')
regexp = re.compile(r'^(\d+)[\t ]+(\d+)[ \t]+([><]{2})?$')
cleaned_data = []
for i, line in enumerate(data):
match = regexp.match(line)
if not match:
raise forms.ValidationError(f"Error in restraints in line {i + 1}")
else:
rst_1, rst_2, loop_type = match.groups()
rst_1 = int(rst_1)
rst_2 = int(rst_2)
cleaned_data.append((rst_1, rst_2, loop_type))
return cleaned_data
I'm using Django 2.1, python 3.7.1, PyCharm 2018.3.3 Professional
I tried to run it under debugger in PyCharm but things goes crazy. I receive different error message. It looks like debugger stopped after full form validation ignoring breakpoints. I have no idea what is going on.
You should test the results of the validation process.
form = NewTaskForm(dict(restraints="90 20 <>"))
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['restraints'], "Error in restraints in line 1")
Ok, I found what was wrong.
form.cleaned_data is created in full_clean(). Not in constructor as I thought. It also calls every clean_fieldname(). So the ugly workaround is something like this:
def test_clean_restraints(self):
initial_data = dict(restraints="90 20 <>")
form = NewTaskForm()
form.cleaned_data = initial_data
form.clean_restraints()
(...)

Django 2 Test: Created object cannot be gotten for tests

I've read about building programs starting with tests, so I thought I'd give it a shot. I've made my initial project and app and a model, but when I try to run a test, I get a "Does not exist" error. I've run the migrations, is there more I have to do before I can run a test? Here's my code:
models.py
from django.db import models
class Name(models.Model):
first_name = models.CharField(
"First Name",
max_length=100,
)
middle_name = models.CharField(
"Middle Name or Initial",
max_length=100,
default='',
)
last_name = models.CharField(
"Last Name",
max_length=200,
)
def __str__(self):
return f'{self.last_name}, {self.first_name}'
tests.py
from django.test import TestCase
from contacts.models import Name
class TestNameModel(TestCase):
#classmethod
def setupTestData(cls):
Name.objects.create(first_name='Banny', last_name='Banvil')
def test_name_exists(self):
name = Name.objects.get(id=1)
print (name)
And the error that I get:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E
======================================================================
ERROR: test_name_exists (contacts.tests.TestNameModel)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/CrazyCarl/Software/contact/contacts/tests.py", line 12, in test_name_exists
name = Name.objects.get(id=1)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/query.py", line 403, in get
self.model._meta.object_name
contacts.models.DoesNotExist: Name matching query does not exist.
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (errors=1)
Destroying test database for alias 'default'...
I tried making an object in the terminal to see if it was working:
>>>from contacts.models import Name
>>>Name.objects.create(last_name='John', first_name='Smith')
<Name: John, Smith>
>>>Name.objects.all()
<QuerySet [<Name: John, Smith>]>
>>>n = Name.objects.get(id=1)
>>>print (n)
John, Smith
What am I missing?
It's better to use fixtures. Basically you have nothing in your db when you try do get(id=1)
Also fixtures will save your time in the feature. Good luck!
It’s setUpTestData not setupTestData

Django test client, not creating models (--keepdb option being used)

I'm trying to setup some models in the test database and then post to a custom form which includes a file upload.
Nothing seems to be persisting in the database, and I'm unsure about why the test when I perform the POST is sending back a 200 response? With follow=False, shouldn't it be a 302?
Also, when I try to look for the model in the database, it finds nothing.
And when I look at the database when using the --keepdb option, nothing is there either?
What am I doing wrong?
class ImportTestCase(TestCase):
remote_data_url = "http://test_data.csv"
local_data_path = "test_data.csv"
c = Client()
password = "password"
def setUp(self):
utils.download_file_if_not_exists(self.remote_data_url, self.local_data_path)
self.my_admin = User.objects.create_superuser('jonny', 'jonny#testclient.com', self.password)
self.c.login(username=self.my_admin.username, password=self.password)
def test_create_organisation(self):
self.o = Organization.objects.create(**{'name': 'TEST ORG'})
def test_create_station(self):
self.s = Station.objects.create(**{'name': 'Player', 'organization_id': 1})
def test_create_window(self):
self.w = Window.objects.create(**{'station_id': 1})
def test_create_component(self):
self.c = Component.objects.create(**{
'type': 'Player',
'window_id': 1,
'start': datetime.datetime.now(),
'end': datetime.datetime.now(),
'json': "",
'layer': 0}
)
def test_csv_import(self):
"""Testing that standard csv imports work"""
self.assertTrue(os.path.exists(self.local_data_path))
with open(self.local_data_path) as fp:
response = self.c.post('/schedule/schedule-import/create/', {
'component': self.c,
'csv': fp,
'date_from': datetime.datetime.now(),
'date_to': datetime.datetime.now()
}, follow=False)
self.assertEqual(response.status_code, 200)
def test_record_exists(self):
new_component = Component.objects.all()
self.assertTrue(len(new_component) > 0)
And the test results
Using existing test database for alias 'default'...
.....[]
F
======================================================================
FAIL: test_record_exists (schedule.tests.ImportTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 64, in test_record_exists
self.assertTrue(len(new_component) > 0)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 6 tests in 1.250s
FAILED (failures=1)
The --keepdb option means that the database is kept. That means it's quicker to run the tests again because you don't have to recreate the table.s
However, each test method in a TestCase class is run in a transaction which is rolled back after the method has finished. Using --keepdb doesn't change this.
This means that your object created in test_create_component will not be seen by the test_record_exists test. You can either create the object inside the test_record_exists method, or in the setUp method or setUpTestData classmethod.

TypeError: object is not iterable when creating object

probably it's too late because I totaly do not understand this error. I created two new classes in models.py:
class SuggestionEmailSent(models.Model):
user = models.OneToOneField(User, related_name='suggestion_sent')
frequency = models.CharField(max_length=10, choices=EMAIL_FREQUENCY_CHOICES, default=EMAIL_FREQUENCY_CHOICES[0][0])
date = models.DateField(default=timezone.now)
class Meta:
unique_together = ("user", "date")
class SuggestionEmailContent(models.Model):
percentage = models.IntegerField()
buy_stock = models.ForeignKey('stocks.Stock', related_name='suggestion_email_buy_stock')
sell_stock = models.ForeignKey('stocks.Stock', related_name='suggestion_email_sell_stock')
portfolio = models.OneToOneField('portfolio.Portfolio', unique=True)
suggestion_sent = models.ForeignKey(SuggestionEmailSent, related_name='contents')
And then I have a code:
try:
content = user.suggestion_sent.contents.get(portfolio=portfolio)
print content.sell_stock
except ObjectDoesNotExist: #mail not sent for this portfolio, send and save
content, created = SuggestionEmailContent.objects.create(percentage=percentage,
buy_stock=suggestion,
sell_stock=rank,
portfolio=portfolio,
suggestion_sent=user.suggestion_sent)
And this is error traceback:
Traceback (most recent call last):
File "./test.py", line 49, in <module>
send_suggestion_email(User.objects.get(id=1))
File "/var/www/django/digrin/wsgi/digrin/suggestion/utils.py", line 192, in send_suggestion_email
suggestion_sent=user.suggestion_sent)
TypeError: 'SuggestionEmailContent' object is not iterable
What does this mean? Error fires up when ObjectDoesNotExist and I want to create new object SuggestionEmailContent. user.suggestion_set is of type <class 'suggestion.models.SuggestionEmailSent'> as it should be. What am I missing? I am using django 1.8
Edit1:
Here is my test.py:
if __name__ == '__main__':
from suggestion.utils import *
send_suggestion_email(User.objects.get(id=1))
and this is my send_suggestion_email:
def send_suggestion_email(user):
percentage = 100
for portfolio in Portfolio.objects.filter(testing=False, user=user):
dividends, monthly_shares = get_portfolio_month_shares(portfolio)
shares_price = get_portfolio_current_year_price(monthly_shares)
suggestions, ranks = get_suggestion_data(portfolio=portfolio, shares=monthly_shares)
if not suggestions or not ranks:
print "no suggestions nor ranks for portfolio" + str(portfolio.id)
continue
suggestion, rank = suggestions.keys()[0], ranks.keys()[0]
try:
content = user.suggestion_sent.contents.get(portfolio=portfolio)
print content.sell_stock
except ObjectDoesNotExist: #mail not sent for this portfolio, send and save
content, created = SuggestionEmailContent.objects.create(percentage=percentage,
buy_stock=suggestion,
sell_stock=rank,
portfolio=portfolio,
suggestion_sent=user.suggestion_sent)
create only returns the created instance instead of (instance, created), so your assignment tries to unpack it.
get_or_create on the other hand does return (instance, created).