Skip to content

Commit

Permalink
Fixed related_name to not conflit with other apps
Browse files Browse the repository at this point in the history
  • Loading branch information
AlvaroLQueiroz committed Apr 21, 2024
1 parent 21c0a63 commit b1827ca
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 38 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Expand Up @@ -3,13 +3,15 @@
## 2.0.0
- Migrated to Github CI
- Added docker environment and migrated to Poetry and pyproject.toml
- Added verbose_name migration
- Migrated from `jsonfield` to Django `JSONField`
- Converted the `level` field from a `CharField` to an `IntegerField`
- Added **verbose_name** migration
- Migrated the **data** field from `jsonfield` to Django `JSONField`
- Converted the **level** field from a `CharField` to an `IntegerField`
- Extracted and improved the sample code
- Fixed variable types on JS code
- Added `/all/` for the path to all notifications
- Remove slug2id and id2slug
- Changed **related_name** from `notifications` to `%(app_label)s_%(class)s_related` (default: `notifications_notification_related`)
- Changed **related_query_name** from `notifications` to `%(app_label)s_%(class)s` (default: `notifications_notification`)

## 1.8.0

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -13,7 +13,7 @@ server:
run: server

migrations:
poetry run python manage.py makemigrations
poetry run python notifications/manage.py makemigrations

migrate:
poetry run python manage.py migrate
Expand Down
5 changes: 4 additions & 1 deletion README.md
Expand Up @@ -184,7 +184,8 @@ can do:

```python
user = User.objects.get(pk=pk)
user.notifications.unread()
user.notifications_notification_related.unread()
# user.<your_app_name>_<your_model_name>_related.unread() # If you are using a custom model
```

There are some other QuerySet methods, too.
Expand Down Expand Up @@ -477,6 +478,8 @@ You will require to define `NOTIFICATIONS_NOTIFICATION_MODEL` setting in
NOTIFICATIONS_NOTIFICATION_MODEL = 'your_app.Notification'
```

> If you are using a custom notification model, your **related_name** will change to `<your_app_name>_<your_model_name>_related`.
## Notes

### Email Notification
Expand Down
2 changes: 1 addition & 1 deletion notifications/helpers.py
Expand Up @@ -19,7 +19,7 @@ def get_num_to_fetch(request):
def get_notification_list(request, method_name="all"):
num_to_fetch = get_num_to_fetch(request)
notification_list = []
for notification in getattr(request.user.notifications, method_name)()[0:num_to_fetch]:
for notification in getattr(request.user.notifications_notification_related, method_name)()[0:num_to_fetch]:
struct = model_to_dict(notification)
struct["slug"] = notification.id
if notification.actor:
Expand Down
2 changes: 1 addition & 1 deletion notifications/manage.py
Expand Up @@ -4,7 +4,7 @@
import sys

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "notification.tests.settings_for_tests")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "notifications.tests.settings_for_tests")
from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
@@ -0,0 +1,61 @@
# Generated by Django 4.2.11 on 2024-04-21 14:38

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("contenttypes", "0002_remove_content_type_name"),
("notifications", "0014_rename_new_level_notification_level"),
]

operations = [
migrations.AlterField(
model_name="notification",
name="action_object_content_type",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="%(app_label)s_%(class)s_action_object_related",
to="contenttypes.contenttype",
verbose_name="action object content type",
),
),
migrations.AlterField(
model_name="notification",
name="actor_content_type",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="%(app_label)s_%(class)s_actor_related",
to="contenttypes.contenttype",
verbose_name="actor content type",
),
),
migrations.AlterField(
model_name="notification",
name="recipient",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)s",
to=settings.AUTH_USER_MODEL,
verbose_name="recipient",
),
),
migrations.AlterField(
model_name="notification",
name="target_content_type",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="%(app_label)s_%(class)s_target_related",
to="contenttypes.contenttype",
verbose_name="target content type",
),
),
]
12 changes: 8 additions & 4 deletions notifications/models/base.py
Expand Up @@ -57,14 +57,18 @@ class AbstractNotification(models.Model):
recipient = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="notifications",
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)s",
verbose_name=_("recipient"),
blank=False,
)
unread = models.BooleanField(_("unread"), default=True, blank=False, db_index=True)

actor_content_type = models.ForeignKey(
ContentType, on_delete=models.CASCADE, related_name="notify_actor", verbose_name=_("actor content type")
ContentType,
on_delete=models.CASCADE,
related_name="%(app_label)s_%(class)s_actor_related",
verbose_name=_("actor content type"),
)
actor_object_id = models.CharField(_("actor object id"), max_length=255)
actor = GenericForeignKey("actor_content_type", "actor_object_id")
Expand All @@ -76,7 +80,7 @@ class AbstractNotification(models.Model):
target_content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
related_name="notify_target",
related_name="%(app_label)s_%(class)s_target_related",
verbose_name=_("target content type"),
blank=True,
null=True,
Expand All @@ -88,7 +92,7 @@ class AbstractNotification(models.Model):
action_object_content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
related_name="notify_action_object",
related_name="%(app_label)s_%(class)s_action_object_related",
verbose_name=_("action object content type"),
blank=True,
null=True,
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion notifications/querysets.py
Expand Up @@ -4,8 +4,8 @@
from django.db import models
from django.utils.translation import gettext_lazy as _

from notifications.notification_types import AbstractUser
from notifications.settings import notification_settings
from notifications.types import AbstractUser


def assert_soft_delete() -> None:
Expand Down
6 changes: 4 additions & 2 deletions notifications/templatetags/notifications_tags.py
Expand Up @@ -12,7 +12,9 @@

def get_cached_notification_unread_count(user):
return cache.get_or_set(
"cache_notification_unread_count", user.notifications.unread().count, notification_settings.CACHE_TIMEOUT
"cache_notification_unread_count",
user.notifications_notification_related.unread().count,
notification_settings.CACHE_TIMEOUT,
)


Expand All @@ -27,7 +29,7 @@ def notifications_unread(context):
@register.filter
def has_notification(user):
if user:
return user.notifications.unread().exists()
return user.notifications_notification_related.unread().exists()
return False


Expand Down
44 changes: 30 additions & 14 deletions notifications/tests/tests.py
Expand Up @@ -82,29 +82,37 @@ def test_all_messages_page(self):
response = self.client.get(reverse("notifications:all"))

self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.all()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.all())
)

def test_unread_messages_pages(self):
self.login("to", "pwd")
response = self.client.get(reverse("notifications:unread"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.unread()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.unread())
)
self.assertEqual(len(response.context["notifications"]), self.message_count)

for index, notification in enumerate(self.to_user.notifications.all()):
for index, notification in enumerate(self.to_user.notifications_notification_related.all()):
if index % 3 == 0:
response = self.client.get(reverse("notifications:mark_as_read", args=[notification.id]))
self.assertEqual(response.status_code, 302)

response = self.client.get(reverse("notifications:unread"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.unread()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.unread())
)
self.assertTrue(len(response.context["notifications"]) < self.message_count)

response = self.client.get(reverse("notifications:mark_all_as_read"))
self.assertRedirects(response, reverse("notifications:unread"))
response = self.client.get(reverse("notifications:unread"))
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.unread()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.unread())
)
self.assertEqual(len(response.context["notifications"]), 0)

def test_next_pages(self):
Expand All @@ -119,7 +127,7 @@ def test_next_pages(self):
)
self.assertRedirects(response, reverse("notifications:unread") + query_parameters)

slug = self.to_user.notifications.first().id
slug = self.to_user.notifications_notification_related.first().id
response = self.client.get(
reverse("notifications:mark_as_read", args=[slug]),
data={
Expand All @@ -128,7 +136,7 @@ def test_next_pages(self):
)
self.assertRedirects(response, reverse("notifications:unread") + query_parameters)

slug = self.to_user.notifications.first().id
slug = self.to_user.notifications_notification_related.first().id
response = self.client.get(
reverse("notifications:mark_as_unread", args=[slug]),
{
Expand All @@ -137,7 +145,7 @@ def test_next_pages(self):
)
self.assertRedirects(response, reverse("notifications:unread") + query_parameters)

@override_settings(ALLOWED_HOSTS=["www.notifications.com"])
@override_settings(ALLOWED_HOSTS=["www.notifications_notification_related.com"])
def test_malicious_next_pages(self):
self.client.force_login(self.to_user)
query_parameters = "?var1=hello&var2=world"
Expand All @@ -154,36 +162,44 @@ def test_malicious_next_pages(self):
def test_delete_messages_pages(self):
self.login("to", "pwd")

slug = self.to_user.notifications.first().id
slug = self.to_user.notifications_notification_related.first().id
response = self.client.get(reverse("notifications:delete", args=[slug]))
self.assertRedirects(response, reverse("notifications:all"))

response = self.client.get(reverse("notifications:all"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.all()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.all())
)
self.assertEqual(len(response.context["notifications"]), self.message_count - 1)

response = self.client.get(reverse("notifications:unread"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.unread()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.unread())
)
self.assertEqual(len(response.context["notifications"]), self.message_count - 1)

@override_settings(DJANGO_NOTIFICATIONS_CONFIG={"SOFT_DELETE": True})
def test_soft_delete_messages_manager(self):
self.login("to", "pwd")

slug = self.to_user.notifications.first().id
slug = self.to_user.notifications_notification_related.first().id
response = self.client.get(reverse("notifications:delete", args=[slug]))
self.assertRedirects(response, reverse("notifications:all"))

response = self.client.get(reverse("notifications:all"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.active()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.active())
)
self.assertEqual(len(response.context["notifications"]), self.message_count - 1)

response = self.client.get(reverse("notifications:unread"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context["notifications"]), len(self.to_user.notifications.unread()))
self.assertEqual(
len(response.context["notifications"]), len(self.to_user.notifications_notification_related.unread())
)
self.assertEqual(len(response.context["notifications"]), self.message_count - 1)

def test_unread_count_api(self):
Expand Down
19 changes: 11 additions & 8 deletions notifications/views.py
Expand Up @@ -34,20 +34,20 @@ class AllNotificationsList(NotificationViewList):

def get_queryset(self):
if notification_settings.SOFT_DELETE:
qset = self.request.user.notifications.active()
qset = self.request.user.notifications_notification_related.active()
else:
qset = self.request.user.notifications.all()
qset = self.request.user.notifications_notification_related.all()
return qset


class UnreadNotificationsList(NotificationViewList):
def get_queryset(self):
return self.request.user.notifications.unread()
return self.request.user.notifications_notification_related.unread()


@login_required
def mark_all_as_read(request):
request.user.notifications.mark_all_as_read()
request.user.notifications_notification_related.mark_all_as_read()

_next = request.GET.get("next")

Expand Down Expand Up @@ -112,7 +112,7 @@ def live_unread_notification_count(request):
data = {"unread_count": 0}
else:
data = {
"unread_count": request.user.notifications.unread().count(),
"unread_count": request.user.notifications_notification_related.unread().count(),
}
return JsonResponse(data)

Expand All @@ -126,7 +126,10 @@ def live_unread_notification_list(request):

unread_list = get_notification_list(request, "unread")

data = {"unread_count": request.user.notifications.unread().count(), "unread_list": unread_list}
data = {
"unread_count": request.user.notifications_notification_related.unread().count(),
"unread_list": unread_list,
}
return JsonResponse(data)


Expand All @@ -139,7 +142,7 @@ def live_all_notification_list(request):

all_list = get_notification_list(request)

data = {"all_count": request.user.notifications.count(), "all_list": all_list}
data = {"all_count": request.user.notifications_notification_related.count(), "all_list": all_list}
return JsonResponse(data)


Expand All @@ -148,6 +151,6 @@ def live_all_notification_count(request):
data = {"all_count": 0}
else:
data = {
"all_count": request.user.notifications.count(),
"all_count": request.user.notifications_notification_related.count(),
}
return JsonResponse(data)
4 changes: 2 additions & 2 deletions sample_website/views.py
Expand Up @@ -17,8 +17,8 @@ def live_tester(request):
request,
"test_live.html",
{
"unread_count": request.user.notifications.unread().count(),
"notifications": request.user.notifications.all(),
"unread_count": request.user.notifications_notification_related.unread().count(),
"notifications": request.user.notifications_notification_related.all(),
},
)

Expand Down

0 comments on commit b1827ca

Please sign in to comment.