Skip to content

Commit

Permalink
Merge pull request #18 from stuartmaxwell/dev
Browse files Browse the repository at this point in the history
Category model refactor
  • Loading branch information
stuartmaxwell authored Jun 21, 2024
2 parents 7fb9396 + 5680ba6 commit 14dcadf
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 100 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.6 on 2024-06-21 03:11

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("djpress", "0003_post_menu_order"),
]

operations = [
migrations.RenameField(
model_name="category",
old_name="name",
new_name="title",
),
migrations.AddField(
model_name="category",
name="menu_order",
field=models.IntegerField(default=0),
),
]
9 changes: 5 additions & 4 deletions djpress/models/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ def get_category_by_slug(self: "CategoryManager", slug: str) -> "Category":
class Category(models.Model):
"""Category model."""

name = models.CharField(max_length=100)
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True, blank=True)
description = models.TextField(blank=True)
menu_order = models.IntegerField(default=0)

# Custom Manager
objects: "CategoryManager" = CategoryManager()
Expand All @@ -71,14 +72,14 @@ class Meta:

def __str__(self: "Category") -> str:
"""Return the string representation of the category."""
return self.name
return self.title

def save(self: "Category", *args, **kwargs) -> None: # noqa: ANN002, ANN003
"""Override the save method to auto-generate the slug."""
if not self.slug:
self.slug = slugify(self.name)
self.slug = slugify(self.title)
if not self.slug or self.slug.strip("-") == "":
msg = "Invalid name. Unable to generate a valid slug."
msg = "Invalid title. Unable to generate a valid slug."
raise ValueError(msg)

try:
Expand Down
2 changes: 1 addition & 1 deletion djpress/templates/djpress/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h1>{% blog_title_link %}</h1>

<main>

{% category_name "h1" pre_text="View Posts in the " post_text=" Category" %}
{% category_title "h1" pre_text="View Posts in the " post_text=" Category" %}
{% author_name "h1" pre_text="View Posts by " %}

{% if post %}
Expand Down
18 changes: 9 additions & 9 deletions djpress/templatetags/djpress_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def get_categories() -> models.QuerySet[Category] | None:
Returns:
models.QuerySet[Category]: All categories.
"""
return Category.objects.get_categories()
return Category.objects.get_categories().order_by("menu_order").order_by("title")


@register.simple_tag
Expand Down Expand Up @@ -165,7 +165,7 @@ def blog_page_title(
post: Post | None = context.get("post")

if category:
page_title = category.name
page_title = category.title

elif author:
page_title = get_author_display_name(author)
Expand Down Expand Up @@ -329,7 +329,7 @@ def post_category_link(category: Category, link_class: str = "") -> str:
link_class: The CSS class(es) for the link.
"""
if not settings.CATEGORY_PATH_ENABLED:
return category.name
return category.title

return mark_safe(category_link(category, link_class))

Expand Down Expand Up @@ -452,14 +452,14 @@ def post_content(


@register.simple_tag(takes_context=True)
def category_name(
def category_title(
context: Context,
outer: str = "",
outer_class: str = "",
pre_text: str = "",
post_text: str = "",
) -> str:
"""Return the name of a category.
"""Return the title of a category.
Expects there to be an `category` in the context set to a Category object. If
there's no category in the context or category is not a Category object, then retun
Expand All @@ -470,11 +470,11 @@ def category_name(
context: The context.
outer: The outer HTML tag for the category.
outer_class: The CSS class(es) for the outer tag.
pre_text: The text to prepend to the category name.
post_text: The text to append to the category name.
pre_text: The text to prepend to the category title.
post_text: The text to append to the category title.
Returns:
str: The name of the category formatted with the outer tag and class if
str: The title of the category formatted with the outer tag and class if
provided.
"""
category: Category | None = context.get("category")
Expand All @@ -485,7 +485,7 @@ def category_name(
allowed_outer_tags = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "div", "span"]
outer_class = f' class="{outer_class}"' if outer_class else ""

output = category.name
output = category.title

if pre_text:
output = f"{pre_text}{output}"
Expand Down
4 changes: 2 additions & 2 deletions djpress/templatetags/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ def category_link(category: Category, link_class: str = "") -> str:
link_class_html = f' class="{link_class}"' if link_class else ""

return (
f'<a href="{category_url}" title="View all posts in the {category.name} '
f'category"{link_class_html}>{ category.name }</a>'
f'<a href="{category_url}" title="View all posts in the {category.title} '
f'category"{link_class_html}>{ category.title }</a>'
)


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "djpress"
version = "0.7.2"
version = "0.8.0"
authors = [{ name = "Stuart Maxwell", email = "[email protected]" }]
description = "A blog application for Django sites, inspired by classic WordPress."
readme = "README.md"
Expand Down
20 changes: 10 additions & 10 deletions tests/test_cache_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def test_get_cached_categories():
assert settings.CACHE_CATEGORIES is True

# Create some test categories
Category.objects.create(name="Category 1")
Category.objects.create(name="Category 2")
Category.objects.create(title="Category 1")
Category.objects.create(title="Category 2")

# Call the get_cached_categories method
queryset = Category.objects._get_cached_categories()
Expand All @@ -38,7 +38,7 @@ def test_cache_invalidation_on_save():
assert settings.CACHE_CATEGORIES is True

# Create a test category
category = Category.objects.create(name="Category 1")
category = Category.objects.create(title="Category 1")

# Call the get_cached_categories method
queryset = Category.objects._get_cached_categories()
Expand All @@ -49,7 +49,7 @@ def test_cache_invalidation_on_save():
assert len(queryset) == 1

# Modify the category and save it
category.name = "Updated Category"
category.title = "Updated Category"
category.save()

# Assert that the cache is invalidated
Expand All @@ -63,7 +63,7 @@ def test_cache_invalidation_on_save():
cached_queryset2 = cache.get(CATEGORY_CACHE_KEY)
assert cached_queryset2 is not None
assert len(queryset2) == 1
assert queryset2[0].name == "Updated Category"
assert queryset2[0].title == "Updated Category"


@pytest.mark.django_db
Expand All @@ -72,7 +72,7 @@ def test_cache_invalidation_on_delete():
assert settings.CACHE_CATEGORIES is True

# Create a test category
category = Category.objects.create(name="Category 1")
category = Category.objects.create(title="Category 1")

# Call the get_cached_categories method
queryset = Category.objects._get_cached_categories()
Expand Down Expand Up @@ -104,8 +104,8 @@ def test_cache_get_category_by_slug():
# Confirm the settings in settings_testing.py
assert settings.CACHE_CATEGORIES is True

category1 = Category.objects.create(name="Category 1", slug="category-1")
category2 = Category.objects.create(name="Category 2", slug="category-2")
category1 = Category.objects.create(title="Category 1", slug="category-1")
category2 = Category.objects.create(title="Category 2", slug="category-2")

category = Category.objects.get_category_by_slug("category-1")

Expand All @@ -119,8 +119,8 @@ def test_cache_get_category_by_slug_not_in_cache():
# Confirm the settings in settings_testing.py
assert settings.CACHE_CATEGORIES is True

category1 = Category.objects.create(name="Category 1", slug="category-1")
category2 = Category.objects.create(name="Category 2", slug="category-2")
category1 = Category.objects.create(title="Category 1", slug="category-1")
category2 = Category.objects.create(title="Category 2", slug="category-2")

# Call the get_cached_categories method
queryset = Category.objects._get_cached_categories()
Expand Down
54 changes: 27 additions & 27 deletions tests/test_models_category.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@

@pytest.mark.django_db
def test_category_model():
category = Category.objects.create(name="Test Category", slug="test-category")
assert category.name == "Test Category"
category = Category.objects.create(title="Test Category", slug="test-category")
assert category.title == "Test Category"
assert category.slug == "test-category"
assert str(category) == "Test Category"


@pytest.mark.django_db
def test_category_save_slug_generation():
"""Test that the slug is correctly generated when saving a Category."""
category = Category(name="Test Category")
category = Category(title="Test Category")
category.save()

assert category.slug == slugify("Test Category")
Expand All @@ -26,10 +26,10 @@ def test_category_save_slug_generation():
@pytest.mark.django_db
def test_category_save_slug_uniqueness():
"""Test that an error is raised when trying to save a Category with a duplicate slug."""
category1 = Category(name="Test Category")
category1 = Category(title="Test Category")
category1.save()

category2 = Category(name="Test Category")
category2 = Category(title="Test Category")

with pytest.raises(ValueError) as excinfo:
category2.save()
Expand All @@ -43,48 +43,48 @@ def test_category_save_slug_uniqueness():
@pytest.mark.django_db
def test_category_save_invalid_name():
"""Test that an error is raised when trying to save a Category with an invalid name."""
category = Category(name="-")
category = Category(title="-")

with pytest.raises(ValueError) as excinfo:
category.save()

assert str(excinfo.value) == "Invalid name. Unable to generate a valid slug."
assert str(excinfo.value) == "Invalid title. Unable to generate a valid slug."


@pytest.mark.django_db
def test_category_slug_auto_generation():
# Test case 1: Slug auto-generated when not provided
category1 = Category.objects.create(name="Test Category")
assert category1.slug == slugify(category1.name)
category1 = Category.objects.create(title="Test Category")
assert category1.slug == slugify(category1.title)

# Test case 2: Slug not overridden when provided
category2 = Category.objects.create(name="Another Category", slug="custom-slug")
category2 = Category.objects.create(title="Another Category", slug="custom-slug")
assert category2.slug == "custom-slug"

# Test case 3: Slug auto-generated with special characters
category3 = Category.objects.create(name="Special !@#$%^&*() Category")
category3 = Category.objects.create(title="Special !@#$%^&*() Category")
assert category3.slug == "special-category"

# Test case 4: Slug auto-generated with non-ASCII characters
category4 = Category.objects.create(name="Non-ASCII áéíóú Category")
category4 = Category.objects.create(title="Non-ASCII áéíóú Category")
assert category4.slug == "non-ascii-aeiou-category"

# Test case 5: Slug auto-generated with leading/trailing hyphens
category5 = Category.objects.create(name="--Leading/Trailing Hyphens--")
category5 = Category.objects.create(title="--Leading/Trailing Hyphens--")
assert category5.slug == "leadingtrailing-hyphens"

# Test case 6: Raise ValueError for invalid name
# Test case 6: Raise ValueError for invalid title
with pytest.raises(ValueError) as exc_info:
Category.objects.create(name="!@#$%^&*()")
assert str(exc_info.value) == "Invalid name. Unable to generate a valid slug."
Category.objects.create(title="!@#$%^&*()")
assert str(exc_info.value) == "Invalid title. Unable to generate a valid slug."


@pytest.mark.django_db
def test_get_categories_cache_enabled():
"""Test that the get_categories method returns the correct categories."""
category1 = Category.objects.create(name="Category 1")
category2 = Category.objects.create(name="Category 2")
category3 = Category.objects.create(name="Category 3")
category1 = Category.objects.create(title="Category 1")
category2 = Category.objects.create(title="Category 2")
category3 = Category.objects.create(title="Category 3")

# Confirm the settings in settings_testing.py
assert settings.CACHE_CATEGORIES is True
Expand All @@ -97,9 +97,9 @@ def test_get_categories_cache_enabled():
@pytest.mark.django_db
def test_get_categories_cache_disabled():
"""Test that the get_categories method returns the correct categories."""
category1 = Category.objects.create(name="Category 1")
category2 = Category.objects.create(name="Category 2")
category3 = Category.objects.create(name="Category 3")
category1 = Category.objects.create(title="Category 1")
category2 = Category.objects.create(title="Category 2")
category3 = Category.objects.create(title="Category 3")

# Confirm the settings in settings_testing.py
assert settings.CACHE_CATEGORIES is True
Expand All @@ -120,8 +120,8 @@ def test_get_category_by_slug_cache_enabled():
# Confirm the settings in settings_testing.py
assert settings.CACHE_CATEGORIES is True

category1 = Category.objects.create(name="Category 1", slug="category-1")
category2 = Category.objects.create(name="Category 2", slug="category-2")
category1 = Category.objects.create(title="Category 1", slug="category-1")
category2 = Category.objects.create(title="Category 2", slug="category-2")

category = Category.objects.get_category_by_slug("category-1")

Expand All @@ -138,8 +138,8 @@ def test_get_category_by_slug_cache_disabled():
settings.set("CACHE_CATEGORIES", False)
assert settings.CACHE_CATEGORIES is False

category1 = Category.objects.create(name="Category 1", slug="category-1")
category2 = Category.objects.create(name="Category 2", slug="category-2")
category1 = Category.objects.create(title="Category 1", slug="category-1")
category2 = Category.objects.create(title="Category 2", slug="category-2")

category = Category.objects.get_category_by_slug("category-1")

Expand Down Expand Up @@ -175,7 +175,7 @@ def test_category_permalink():
assert settings.CATEGORY_PATH_ENABLED is True
assert settings.CATEGORY_PATH == "test-url-category"

category = Category.objects.create(name="Test Category", slug="test-category")
category = Category.objects.create(title="Test Category", slug="test-category")

assert category.permalink == "test-url-category/test-category"

Expand Down
6 changes: 3 additions & 3 deletions tests/test_models_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ def user():

@pytest.fixture
def category1():
return Category.objects.create(name="Test Category1", slug="test-category1")
return Category.objects.create(title="Test Category1", slug="test-category1")


@pytest.fixture
def category2():
return Category.objects.create(name="Test Category2", slug="test-category2")
return Category.objects.create(title="Test Category2", slug="test-category2")


@pytest.fixture
Expand Down Expand Up @@ -165,7 +165,7 @@ def test_get_published_post_by_slug_with_future_date(user):

@pytest.mark.django_db
def test_get_published_content_by_category_with_future_date(user):
category = Category.objects.create(name="Test Category", slug="test-category")
category = Category.objects.create(title="Test Category", slug="test-category")
Post.post_objects.create(
title="Past Post",
slug="past-post",
Expand Down
Loading

0 comments on commit 14dcadf

Please sign in to comment.