Coverage for catalog/models.py: 91.78%

69 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-13 15:39 -0700

1import uuid 

2from datetime import date 

3 

4from django.contrib.auth import get_user_model 

5from django.db import models 

6from django.urls import reverse 

7 

8 

9class Genre(models.Model): 

10 name = models.CharField(max_length=200, help_text="Enter a book genre") 

11 

12 class Meta: 

13 ordering = ["name"] 

14 

15 def __str__(self): 

16 return self.name 1m

17 

18 

19class Language(models.Model): 

20 name = models.CharField(max_length=200, help_text="Enter the book's language") 

21 

22 class Meta: 

23 ordering = ["name"] 

24 

25 def __str__(self): 

26 return self.name 1n

27 

28 

29class Book(models.Model): 

30 title = models.CharField(max_length=200) 

31 author = models.ForeignKey("Author", on_delete=models.SET_NULL, null=True) 

32 pages = models.IntegerField(null=True, blank=True, help_text="Number of Pages") 

33 publisher = models.CharField(max_length=40, blank=True) 

34 pubdate = models.DateField(null=True, blank=True, help_text="Date Published") 

35 summary = models.TextField( 

36 max_length=1000, help_text="Enter a brief description of the book." 

37 ) 

38 isbn = models.CharField( 

39 "ISBN", 

40 max_length=13, 

41 unique=True, 

42 help_text="13 Character <a href='https://www.isbn-international.org/content/what-isbn'>ISBN number</a>", 

43 ) 

44 genre = models.ManyToManyField(Genre, help_text="Select a genre for this book") 

45 language = models.ForeignKey("Language", on_delete=models.SET_NULL, null=True) 

46 cover = models.ImageField(upload_to="covers/", blank=True) 

47 

48 class Meta: 

49 ordering = ["title", "author"] 

50 

51 def __str__(self): 

52 return self.title 1o

53 

54 def get_absolute_url(self): 

55 return reverse("book-detail", args=[str(self.id)]) 1p

56 

57 def display_genre(self): 

58 """Creates a string for Genre. Required for Admin display""" 

59 return ", ".join([genre.name for genre in self.genre.all()[:3]]) 

60 

61 display_genre.short_description = "Genre" 

62 

63 

64class BookInstance(models.Model): 

65 """Represents a specific copy of a book""" 

66 

67 id = models.UUIDField( 

68 primary_key=True, 

69 default=uuid.uuid4, 

70 help_text="Unique ID for this book across whole library", 

71 ) 

72 book = models.ForeignKey("Book", on_delete=models.RESTRICT, null=True) 

73 imprint = models.CharField(max_length=200) 

74 due_back = models.DateField(null=True, blank=True) 

75 borrower = models.ForeignKey( 

76 get_user_model(), on_delete=models.SET_NULL, null=True, blank=True 

77 ) 

78 

79 LOAN_STATUS = ( 

80 ("m", "Maintenance"), 

81 ("o", "On Loan"), 

82 ("a", "Available"), 

83 ("r", "Reserved"), 

84 ) 

85 

86 status = models.CharField( 

87 max_length=1, 

88 choices=LOAN_STATUS, 

89 blank=True, 

90 default="m", 

91 help_text="Book Availability", 

92 ) 

93 

94 class Meta: 

95 ordering = ["due_back"] 

96 permissions = (("can_mark_returned", "Set book as returned"),) 

97 

98 def __str__(self): 

99 return "{0} ({1})".format(self.id, self.book.title) 

100 

101 @property 

102 def is_overdue(self): 

103 if self.due_back and date.today() > self.due_back: 103 ↛ 104line 103 didn't jump to line 104 because the condition on line 103 was never true1defghijk

104 return True 

105 return False 1defghijk

106 

107 

108class Author(models.Model): 

109 first_name = models.CharField(max_length=100) 

110 middle_name = models.CharField( 

111 max_length=100, blank=True, help_text="Middle Name(initial)" 

112 ) 

113 last_name = models.CharField(max_length=100) 

114 date_of_birth = models.DateField(null=True, blank=True) 

115 date_of_death = models.DateField("Died", null=True, blank=True) 

116 

117 class Meta: 

118 ordering = ["last_name", "first_name"] 

119 

120 def __str__(self): 

121 if self.middle_name is not None: 121 ↛ 124line 121 didn't jump to line 124 because the condition on line 121 was always true1albc

122 return f"{self.last_name}, {self.first_name} {self.middle_name}" 1albc

123 else: 

124 return f"{self.last_name}, {self.first_name}" 

125 

126 def get_absolute_url(self): 

127 return reverse("author-detail", args=[str(self.id)]) 1aqrbc