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
Related
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
I am using Django:
>>> django.VERSION
(1, 11, 15, u'final', 0)
MPTT:
django-mptt 0.9.1
In Models:
from mptt.models import MPTTModel, TreeForeignKey
class Location(MPTTModel):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=75,null=False)
parent = TreeForeignKey('self', on_delete=models.PROTECT, null=True, blank=True)
I can view and add properly as per django-mptt documentation. But I am not able to delete a child node. It messes up all the tree structure.
Here is how delete is used in views:
Location.objects.get(id=loc_id).delete()
where loc_id is the id of the node i want to delete.
I am not sure how to use Delete properly or maybe there is a bug in mptt.
I looked up for any example on its official doc. It says nothing more than the following on this topic:
class mptt.models.MPTTModel(*args, **kwargs)
MPTTModel.delete(*args, **kwargs)
Calling delete on a node will delete it as well as its full subtree, as opposed to reattaching all
the subnodes to its parent node. There are no argument specific to a
MPTT model, all the arguments will be passed directly to the django’s
Model.delete.
delete will not return anything.
Thanks
Once I had this problem with protected children deleting (django-mptt==0.9.1).
After some searching I found out the next issue:
problem occurs inside delete() method of the MPTTodel.
First it tries to update the tree structure, then delete the object. So if we have protected relation, our tree could be messed up.
tree_width = (self._mpttfield('right') -
self._mpttfield('left') + 1)
target_right = self._mpttfield('right')
tree_id = self._mpttfield('tree_id')
self._tree_manager._close_gap(tree_width, target_right, tree_id)
parent = cached_field_value(self, self._mptt_meta.parent_attr)
if parent:
right_shift = -self.get_descendant_count() - 2
self._tree_manager._post_insert_update_cached_parent_right(parent, right_shift)
return super(MPTTModel, self).delete(*args, **kwargs)
I've solved this issue using transactions. Something like:
from django.db import transaction
def delete(self, *args, **kwargs):
with transaction.atomic():
super().delete(*args, **kwargs)
test in shell (django 3.1.7 and django-mptt 0.12.0)
from mptt.models import MPTTModel, TreeForeignKey
from django.db import models, transaction
class Test(MPTTModel):
name = models.TextField()
parent = TreeForeignKey(
'self',
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='children'
)
from testing.models import Test
a = Test.objects.create(name='a')
b = Test.objects.create(name='b', parent=a)
c = Test.objects.create(name='c', parent=b)
print(a.get_descendants())
print(c.get_ancestors())
b.delete()
# refresh from db
a = Test.objects.get(pk=a.pk)
c = Test.objects.get(pk=c.pk)
print(a.get_descendants())
print(c.get_ancestors())
Without transaction:
>>> print(a.get_descendants())
<TreeQuerySet [<Test: Test object (20)>, <Test: Test object (21)>]>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (19)>, <Test: Test object (20)>]>
>>>
>>> b.delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/mptt/models.py", line 1138, in delete
return super().delete(*args, **kwargs)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/base.py", line 946, in delete
collector.collect([self], keep_parents=keep_parents)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/deletion.py", line 302, in collect
raise ProtectedError(
django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Test' because they are referenced through protected foreign keys: 'Test.parent'.", {<Test: Test object (21)>})
>>>
>>> # refresh from db
>>> a = Test.objects.get(pk=a.pk)
>>> c = Test.objects.get(pk=c.pk)
>>>
>>> print(a.get_descendants())
<TreeQuerySet []>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (20)>]>
Within transaction
>>> print(a.get_descendants())
<TreeQuerySet [<Test: Test object (23)>, <Test: Test object (24)>]>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (22)>, <Test: Test object (23)>]>
>>>
>>> b.delete()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vladimir/Desktop/test/someproject/testing/models.py", line 16, in delete
super().delete(*args, **kwargs)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/mptt/models.py", line 1138, in delete
return super().delete(*args, **kwargs)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/base.py", line 946, in delete
collector.collect([self], keep_parents=keep_parents)
File "/home/vladimir/Desktop/test/.venv/lib/python3.8/site-packages/django/db/models/deletion.py", line 302, in collect
raise ProtectedError(
django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Test' because they are referenced through protected foreign keys: 'Test.parent'.", {<Test: Test object (24)>})
>>>
>>> # refresh from db
>>> a = Test.objects.get(pk=a.pk)
>>> c = Test.objects.get(pk=c.pk)
>>>
>>> print(a.get_descendants())
<TreeQuerySet [<Test: Test object (23)>, <Test: Test object (24)>]>
>>> print(c.get_ancestors())
<TreeQuerySet [<Test: Test object (22)>, <Test: Test object (23)>]>
Ok so turns out that for the time being just to get the sane table structure i can use
Location.objects.rebuild()
This rebuilds the whole table structure i.e. its lft, rght columns. So my messed up tree is fine again. I use this line after deleting a node.
This might not be the perfect solution.
I am still looking for a proper delete code because rebuilding tree for a large data set can be time consuming.
Hope somebody can still help in this regard.
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).
My Django app is raising a puzzling error when using a production served version (via Apache, and Nginx for static), that is not evident for the dev server version on localhost.
I have the models :
class AdaptationLibrary(models.Model):
description = models.CharField( u'Description of adaptation',max_length=400,blank=True,null=True)
name = models.CharField(u'Adaptation Name',max_length=60)
applies_to = models.ManyToManyField(Archetype,related_name =u'archetype_adaptations',null=True,blank=True)
adaptations = jsonfield.JSONField(u'adaptation library items', null=True, blank=True)
def __unicode__(self):
return self.name
and ..
class Archetype(models.Model):
archetype = models.CharField(max_length=20, choices=ARCHETYPE_CHOICES,unique=True)
archetype_family = models.CharField(max_length=60,choices=ARCHETYPE_FAMILY_CHOICES,null=True)
replacement_cost_default = models.FloatField("Default complete asset replacement cost - ($)",null=True, blank=True)
lifespan_default = models.FloatField("Default asset life (yrs)", null=True, blank=True)
age_default = models.FloatField("Default age - (yrs)", null=True, blank=True)
storage_time_default = models.FloatField("Default storage/retention time (hrs)", null=True, blank=True)
def __unicode__(self):
return self.archetype
when I attempt to retrieve related Archetype objects via :
library_archetypes = library_item.applies_to.all()
I get the following error :
FieldError: Cannot resolve keyword u'archetype_adaptations' into field.
Choices are: age_default, archetype, archetype_family, asset, cemlo2, id,
lifespan_default, new_dependency, replacement_cost_default, storage_time_default
Dev and local versions are using the same database, and apart from the call to the AdaptationLibrary ManyToManyField, the rest of the app functions fine.
Can anybody shed some light on this issue?
Cheers
Edit:
As per Rohan's suggestion that it's a migration problem - I've gone the whole box and dice of resetting and re-converting to south. Dev server is still happy - Apache served version throws same errors. Both versions are using the same DB.
(full traceback error) :
ERROR Traceback (most recent call last):
File "C:\Python27\Lib\site-packages\dajaxice\core\DajaxiceRequest.py", line 181, in process
response = '%s' % thefunction(self.request, **argv)
File "C:/Python27/sites/Adaptwater\proto4\ajax.py", line 2636, in populate_adaptation_library
initial_data = dict_to_library_form(library_item_id = library_to_load)
File "C:/Python27/sites/Adaptwater\proto4\ajax.py", line 2556, in dict_to_library_form
library_archetypes = library_item.applies_to.all()
File "C:\Python27\Lib\site-packages\django\db\models\manager.py", line 116, in all
return self.get_query_set()
File "C:\Python27\Lib\site-packages\django\db\models\fields\related.py", line 543, in get_query_set
return super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**self.core_filters)
File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 621, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "C:\Python27\Lib\site-packages\django\db\models\query.py", line 639, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "C:\Python27\Lib\site-packages\django\db\models\sql\query.py", line 1250, in add_q
can_reuse=used_aliases, force_having=force_having)
File "C:\Python27\Lib\site-packages\django\db\models\sql\query.py", line 1122, in add_filter
process_extras=process_extras)
File "C:\Python27\Lib\site-packages\django\db\models\sql\query.py", line 1316, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword u'archetype_adaptations' into field. Choices are: age_default, archetype, archetype_family, asset, cemlo2, id, lifespan_default, new_dependency, replacement_cost_default, storage_time_default
Ok - sorry for the self answer, but I fixed the problem, even if I'm still mostly in the dark as to what caused it. After some additional serious googling, I found discussion about the problem in terms of ordering of imports, and model definitions both. For example :
http://chase-seibert.github.com/blog/2010/04/30/django-manytomany-error-cannot-resolve-keyword-xxx-into-a-field.html
After placing the AdaptationLibrary model ahead of Archetype in models.py (and quoting "Archetype" for m2m setup) it appears to be happy. Unless I'm missing something blindingly obvious, this feels like a voodoo fix. Up until now I'd been fastidiously putting referred to models before their referring buddies. But it's a fix nonetheless - so now back to work.
Cheers & Thanks.
Try to use String instead of unicode...sometimes, I have had this problem where Apache is not able to understand UTF-8.
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.