1. from django.db.models import Q
    
  2. from django.http import Http404
    
  3. from django.shortcuts import get_list_or_404, get_object_or_404
    
  4. from django.test import TestCase
    
  5. 
    
  6. from .models import Article, Author
    
  7. 
    
  8. 
    
  9. class GetObjectOr404Tests(TestCase):
    
  10.     def test_get_object_or_404(self):
    
  11.         a1 = Author.objects.create(name="Brave Sir Robin")
    
  12.         a2 = Author.objects.create(name="Patsy")
    
  13. 
    
  14.         # No Articles yet, so we should get an Http404 error.
    
  15.         with self.assertRaises(Http404):
    
  16.             get_object_or_404(Article, title="Foo")
    
  17. 
    
  18.         article = Article.objects.create(title="Run away!")
    
  19.         article.authors.set([a1, a2])
    
  20.         # get_object_or_404 can be passed a Model to query.
    
  21.         self.assertEqual(get_object_or_404(Article, title__contains="Run"), article)
    
  22. 
    
  23.         # We can also use the Article manager through an Author object.
    
  24.         self.assertEqual(
    
  25.             get_object_or_404(a1.article_set, title__contains="Run"), article
    
  26.         )
    
  27. 
    
  28.         # No articles containing "Camelot". This should raise an Http404 error.
    
  29.         with self.assertRaises(Http404):
    
  30.             get_object_or_404(a1.article_set, title__contains="Camelot")
    
  31. 
    
  32.         # Custom managers can be used too.
    
  33.         self.assertEqual(
    
  34.             get_object_or_404(Article.by_a_sir, title="Run away!"), article
    
  35.         )
    
  36. 
    
  37.         # QuerySets can be used too.
    
  38.         self.assertEqual(
    
  39.             get_object_or_404(Article.objects.all(), title__contains="Run"), article
    
  40.         )
    
  41. 
    
  42.         # Just as when using a get() lookup, you will get an error if more than
    
  43.         # one object is returned.
    
  44. 
    
  45.         with self.assertRaises(Author.MultipleObjectsReturned):
    
  46.             get_object_or_404(Author.objects.all())
    
  47. 
    
  48.         # Using an empty QuerySet raises an Http404 error.
    
  49.         with self.assertRaises(Http404):
    
  50.             get_object_or_404(Article.objects.none(), title__contains="Run")
    
  51. 
    
  52.         # get_list_or_404 can be used to get lists of objects
    
  53.         self.assertEqual(
    
  54.             get_list_or_404(a1.article_set, title__icontains="Run"), [article]
    
  55.         )
    
  56. 
    
  57.         # Http404 is returned if the list is empty.
    
  58.         with self.assertRaises(Http404):
    
  59.             get_list_or_404(a1.article_set, title__icontains="Shrubbery")
    
  60. 
    
  61.         # Custom managers can be used too.
    
  62.         self.assertEqual(
    
  63.             get_list_or_404(Article.by_a_sir, title__icontains="Run"), [article]
    
  64.         )
    
  65. 
    
  66.         # QuerySets can be used too.
    
  67.         self.assertEqual(
    
  68.             get_list_or_404(Article.objects.all(), title__icontains="Run"), [article]
    
  69.         )
    
  70.         # Q objects.
    
  71.         self.assertEqual(
    
  72.             get_object_or_404(
    
  73.                 Article,
    
  74.                 Q(title__startswith="Run") | Q(title__startswith="Walk"),
    
  75.                 authors__name__contains="Brave",
    
  76.             ),
    
  77.             article,
    
  78.         )
    
  79.         self.assertEqual(
    
  80.             get_list_or_404(
    
  81.                 Article,
    
  82.                 Q(title__startswith="Run") | Q(title__startswith="Walk"),
    
  83.                 authors__name="Patsy",
    
  84.             ),
    
  85.             [article],
    
  86.         )
    
  87. 
    
  88.     def test_bad_class(self):
    
  89.         # Given an argument klass that is not a Model, Manager, or Queryset
    
  90.         # raises a helpful ValueError message
    
  91.         msg = (
    
  92.             "First argument to get_object_or_404() must be a Model, Manager, or "
    
  93.             "QuerySet, not 'str'."
    
  94.         )
    
  95.         with self.assertRaisesMessage(ValueError, msg):
    
  96.             get_object_or_404("Article", title__icontains="Run")
    
  97. 
    
  98.         class CustomClass:
    
  99.             pass
    
  100. 
    
  101.         msg = (
    
  102.             "First argument to get_object_or_404() must be a Model, Manager, or "
    
  103.             "QuerySet, not 'CustomClass'."
    
  104.         )
    
  105.         with self.assertRaisesMessage(ValueError, msg):
    
  106.             get_object_or_404(CustomClass, title__icontains="Run")
    
  107. 
    
  108.         # Works for lists too
    
  109.         msg = (
    
  110.             "First argument to get_list_or_404() must be a Model, Manager, or "
    
  111.             "QuerySet, not 'list'."
    
  112.         )
    
  113.         with self.assertRaisesMessage(ValueError, msg):
    
  114.             get_list_or_404([Article], title__icontains="Run")
    
  115. 
    
  116.     def test_get_object_or_404_queryset_attribute_error(self):
    
  117.         """AttributeError raised by QuerySet.get() isn't hidden."""
    
  118.         with self.assertRaisesMessage(AttributeError, "AttributeErrorManager"):
    
  119.             get_object_or_404(Article.attribute_error_objects, id=42)
    
  120. 
    
  121.     def test_get_list_or_404_queryset_attribute_error(self):
    
  122.         """AttributeError raised by QuerySet.filter() isn't hidden."""
    
  123.         with self.assertRaisesMessage(AttributeError, "AttributeErrorManager"):
    
  124.             get_list_or_404(Article.attribute_error_objects, title__icontains="Run")