Skip to content

Commit

Permalink
Refactoring : clarifier si une stat vient d'une annotation (gip-inclu…
Browse files Browse the repository at this point in the history
…sion#949)

* Company: update annotated count

* Sector: update annotated count

* Network: update annotated count

* FavoriteList: update annotated count

* Code: update annotated count

* Label: update annotated count

* Conversation: update annotated count

* User: update annotated count

* SiaeGroup: update annotated count

* Siae & Tender: update annotated count

* Fix tests
  • Loading branch information
raphodn authored Oct 26, 2023
1 parent effda9e commit f8db4a8
Show file tree
Hide file tree
Showing 54 changed files with 640 additions and 407 deletions.
4 changes: 2 additions & 2 deletions lemarche/api/networks/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
class NetworkApiTest(TestCase):
@classmethod
def setUpTestData(cls):
NetworkFactory()
NetworkFactory()
NetworkFactory(name="Reseau 1")
NetworkFactory(name="Reseau 2")
UserFactory(api_key="admin")

def test_should_return_network_list(self):
Expand Down
4 changes: 2 additions & 2 deletions lemarche/api/siaes/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def setUpTestData(cls):
kind=siae_constants.KIND_EI, presta_type=[siae_constants.PRESTA_DISP], department="01"
)
siae_with_sector_2.sectors.add(cls.sector_2)
cls.network_1 = NetworkFactory()
cls.network_2 = NetworkFactory()
cls.network_1 = NetworkFactory(name="Reseau 1")
cls.network_2 = NetworkFactory(name="Reseau 2")
siae_with_network_1 = SiaeFactory(
kind=siae_constants.KIND_EI, presta_type=[siae_constants.PRESTA_DISP], department="01"
)
Expand Down
17 changes: 8 additions & 9 deletions lemarche/companies/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.contrib import admin
from django.db.models import Count
from django.urls import reverse
from django.utils.html import format_html, mark_safe
from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
Expand Down Expand Up @@ -42,12 +41,12 @@ def queryset(self, request, queryset):

@admin.register(Company, site=admin_site)
class CompanyAdmin(admin.ModelAdmin, DynamicArrayMixin):
list_display = ["id", "name", "nb_users", "created_at"]
list_display = ["id", "name", "user_count_annotated_with_link", "created_at"]
list_filter = [HasUserFilter, HasEmailDomainFilter]
search_fields = ["id", "name"]
search_help_text = "Cherche sur les champs : ID, Nom"

readonly_fields = ["logo_url_display", "nb_users", "created_at", "updated_at"]
readonly_fields = ["logo_url_display", "user_count_annotated_with_link", "created_at", "updated_at"]

fieldsets = (
(
Expand All @@ -57,13 +56,13 @@ class CompanyAdmin(admin.ModelAdmin, DynamicArrayMixin):
},
),
("Logo", {"fields": ("logo_url", "logo_url_display")}),
("Utilisateurs", {"fields": ("nb_users",)}),
("Utilisateurs", {"fields": ("user_count_annotated_with_link",)}),
("Dates", {"fields": ("created_at", "updated_at")}),
)

def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.annotate(user_count=Count("users", distinct=True))
qs = qs.with_user_stats()
qs = qs.order_by("name")
return qs

Expand All @@ -90,9 +89,9 @@ def logo_url_display(self, instance):

logo_url_display.short_description = "Logo"

def nb_users(self, company):
def user_count_annotated_with_link(self, company):
url = reverse("admin:users_user_changelist") + f"?company__id__exact={company.id}"
return format_html(f'<a href="{url}">{company.user_count}</a>')
return format_html(f'<a href="{url}">{company.user_count_annotated}</a>')

nb_users.short_description = "Nombre d'utilisateurs rattachés"
nb_users.admin_order_field = "user_count"
user_count_annotated_with_link.short_description = "Nombre d'utilisateurs rattachés"
user_count_annotated_with_link.admin_order_field = "user_count_annotated"
5 changes: 5 additions & 0 deletions lemarche/companies/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ class Meta:
name = factory.Faker("company", locale="fr_FR")
# slug: auto-generated
website = "https://example.com"

@factory.post_generation
def users(self, create, extracted, **kwargs):
if extracted:
self.users.add(*extracted)
4 changes: 4 additions & 0 deletions lemarche/companies/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db import models
from django.db.models import Count
from django.template.defaultfilters import slugify
from django.utils import timezone
from django_better_admin_arrayfield.models.fields import ArrayField
Expand All @@ -11,6 +12,9 @@ def has_user(self):
def has_email_domain(self):
return self.exclude(email_domain_list=[])

def with_user_stats(self):
return self.annotate(user_count_annotated=Count("users", distinct=True))


class Company(models.Model):
name = models.CharField(verbose_name="Nom", max_length=255)
Expand Down
16 changes: 16 additions & 0 deletions lemarche/companies/tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.test import TestCase

from lemarche.companies.factories import CompanyFactory
from lemarche.companies.models import Company
from lemarche.users.factories import UserFactory


class CompanyModelTest(TestCase):
Expand All @@ -13,3 +15,17 @@ def test_slug_field(self):

def test_str(self):
self.assertEqual(str(self.company), "Mon entreprise")


class CompanyQuerysetTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.user_1 = UserFactory()
cls.user_2 = UserFactory()
cls.company_with_users = CompanyFactory(users=[cls.user_1, cls.user_2])
cls.company = CompanyFactory()

def test_with_user_stats(self):
company_queryset = Company.objects.with_user_stats()
self.assertEqual(company_queryset.get(id=self.company.id).user_count_annotated, 0)
self.assertEqual(company_queryset.get(id=self.company_with_users.id).user_count_annotated, 2)
25 changes: 17 additions & 8 deletions lemarche/conversations/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ def queryset(self, request, queryset):

@admin.register(Conversation, site=admin_site)
class ConversationAdmin(admin.ModelAdmin):
list_display = ["id", "uuid", "sender_encoded", "is_validate", "title", "kind", "answer_count", "created_at"]
list_display = [
"id",
"uuid",
"sender_encoded",
"is_validate",
"title",
"kind",
"answer_count_annotated",
"created_at",
]
list_filter = ["kind", HasAnswerFilter, IsValidatedFilter]
search_fields = ["id", "uuid", "sender_email"]
search_help_text = "Cherche sur les champs : ID, UUID, Initiateur (E-mail)"
Expand All @@ -61,7 +70,7 @@ class ConversationAdmin(admin.ModelAdmin):
"sender_first_name",
"sender_last_name",
"sender_email",
"answer_count",
"answer_count_annotated",
"data_display",
"created_at",
"updated_at",
Expand All @@ -77,7 +86,7 @@ class ConversationAdmin(admin.ModelAdmin):
"Contenu de la conversation",
{
"fields": (
"answer_count",
"answer_count_annotated",
"data_display",
)
},
Expand All @@ -92,7 +101,7 @@ class Media:

def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.with_answer_count()
qs = qs.with_answer_stats()
return qs

def is_validate(self, conversation: Conversation):
Expand All @@ -101,11 +110,11 @@ def is_validate(self, conversation: Conversation):
is_validate.boolean = True
is_validate.short_description = "Validé"

def answer_count(self, conversation):
return getattr(conversation, "answer_count", 0)
def answer_count_annotated(self, conversation):
return getattr(conversation, "answer_count_annotated", 0)

answer_count.short_description = "Nombre de réponses"
answer_count.admin_order_field = "answer_count"
answer_count_annotated.short_description = "Nombre de réponses"
answer_count_annotated.admin_order_field = "answer_count_annotated"

def response_change(self, request, obj: Conversation):
if request.POST.get("_validate_conversation"):
Expand Down
6 changes: 4 additions & 2 deletions lemarche/conversations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ class ConversationQuerySet(models.QuerySet):
def has_answer(self):
return self.exclude(data=[])

def with_answer_count(self):
return self.annotate(answer_count=Func("data", function="jsonb_array_length", output_field=IntegerField()))
def with_answer_stats(self):
return self.annotate(
answer_count_annotated=Func("data", function="jsonb_array_length", output_field=IntegerField())
)

def get_conv_from_uuid(self, conv_uuid: str, version=1):
"""get conv form
Expand Down
8 changes: 4 additions & 4 deletions lemarche/conversations/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def setUpTestData(cls):
def test_has_answer(self):
self.assertEqual(Conversation.objects.has_answer().count(), 1)

def test_with_answer_count(self):
conversation_queryset = Conversation.objects.with_answer_count()
self.assertEqual(conversation_queryset.get(id=self.conversation.id).answer_count, 0)
self.assertEqual(conversation_queryset.get(id=self.conversation_with_answer.id).answer_count, 1)
def test_with_answer_stats(self):
conversation_queryset = Conversation.objects.with_answer_stats()
self.assertEqual(conversation_queryset.get(id=self.conversation.id).answer_count_annotated, 0)
self.assertEqual(conversation_queryset.get(id=self.conversation_with_answer.id).answer_count_annotated, 1)
21 changes: 13 additions & 8 deletions lemarche/cpv/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.contrib import admin
from django.db.models import Count
from django.urls import reverse
from django.utils.html import format_html

Expand Down Expand Up @@ -27,7 +26,14 @@ def queryset(self, request, queryset):

@admin.register(Code, site=admin_site)
class CodeAdmin(admin.ModelAdmin):
list_display = ["cpv_code", "name", "hierarchy_level", "nb_sectors", "created_at", "updated_at"]
list_display = [
"cpv_code",
"name",
"hierarchy_level",
"sector_count_annotated_with_link",
"created_at",
"updated_at",
]
list_filter = ["hierarchy_level", HasSectorFilter]

autocomplete_fields = ["sectors"]
Expand Down Expand Up @@ -56,13 +62,12 @@ def has_delete_permission(self, request, obj=None):

def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.prefetch_related("sectors")
qs = qs.annotate(sector_count=Count("sectors", distinct=True))
qs = qs.with_sector_stats()
return qs

def nb_sectors(self, code):
def sector_count_annotated_with_link(self, code):
url = reverse("admin:sectors_sector_changelist") + f"?cpv_codes__in={code.id}"
return format_html(f'<a href="{url}">{code.sector_count}</a>')
return format_html(f'<a href="{url}">{code.sector_count_annotated}</a>')

nb_sectors.short_description = "Nombre de secteurs correspondants"
nb_sectors.admin_order_field = "sector_count"
sector_count_annotated_with_link.short_description = "Nombre de secteurs correspondants"
sector_count_annotated_with_link.admin_order_field = "sector_count_annotated"
4 changes: 4 additions & 0 deletions lemarche/cpv/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models import Count
from django.template.defaultfilters import slugify
from django.utils import timezone

Expand All @@ -9,6 +10,9 @@ def has_sector(self):
"""Only return codes who have at least 1 Sector."""
return self.prefetch_related("sectors").filter(sectors__isnull=False).distinct()

def with_sector_stats(self):
return self.annotate(sector_count_annotated=Count("sectors", distinct=True))


class Code(models.Model):
name = models.CharField(verbose_name="Nom", max_length=255)
Expand Down
5 changes: 5 additions & 0 deletions lemarche/cpv/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ def setUpTestData(cls):
def test_has_sector(self):
self.assertEqual(Code.objects.count(), 2)
self.assertEqual(Code.objects.has_sector().count(), 1)

def test_with_sector_stats(self):
code_queryset = Code.objects.with_sector_stats()
self.assertEqual(code_queryset.get(id=self.code.id).sector_count_annotated, 0)
self.assertEqual(code_queryset.get(id=self.code_with_sector.id).sector_count_annotated, 1)
12 changes: 5 additions & 7 deletions lemarche/favorites/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.contrib import admin
from django.db.models import Count
from django.urls import reverse
from django.utils.html import format_html
from fieldsets_with_inlines import FieldsetsInlineMixin
Expand All @@ -17,7 +16,7 @@ class FavoriteItemInline(admin.TabularInline):

@admin.register(FavoriteList, site=admin_site)
class FavoriteListAdmin(FieldsetsInlineMixin, admin.ModelAdmin):
list_display = ["id", "name", "user_with_link", "nb_siaes", "created_at", "updated_at"]
list_display = ["id", "name", "user_with_link", "siae_count_annotated_with_link", "created_at", "updated_at"]
search_fields = ["id", "name", "slug", "user__id", "user__email"]
search_help_text = "Cherche sur les champs : ID, Nom, Slug, Utilisateur (ID, E-mail)"

Expand All @@ -42,8 +41,7 @@ class FavoriteListAdmin(FieldsetsInlineMixin, admin.ModelAdmin):

def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.prefetch_related("siaes")
qs = qs.annotate(siae_count=Count("siaes", distinct=True))
qs = qs.with_siae_stats()
return qs

def user_with_link(self, favorite_list):
Expand All @@ -53,9 +51,9 @@ def user_with_link(self, favorite_list):
user_with_link.short_description = "Utilisateur"
user_with_link.admin_order_field = "user"

def nb_siaes(self, favorite_list):
def siae_count_annotated_with_link(self, favorite_list):
url = reverse("admin:siaes_siae_changelist") + f"?favorite_lists__in={favorite_list.id}"
return format_html(f'<a href="{url}">{favorite_list.siae_count}</a>')

nb_siaes.short_description = "Nombre de structures"
nb_siaes.admin_order_field = "siae_count"
siae_count_annotated_with_link.short_description = "Nombre de structures"
siae_count_annotated_with_link.admin_order_field = "siae_count_annotated"
5 changes: 5 additions & 0 deletions lemarche/favorites/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ class Meta:

name = factory.Faker("company", locale="fr_FR")
# slug: auto-generated

@factory.post_generation
def siaes(self, create, extracted, **kwargs):
if extracted:
self.siaes.add(*extracted)
4 changes: 4 additions & 0 deletions lemarche/favorites/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django.conf import settings
from django.db import models
from django.db.models import Count
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from django.template.defaultfilters import slugify
Expand All @@ -12,6 +13,9 @@ class FavoriteListQuerySet(models.QuerySet):
def by_user(self, user):
return self.filter(user=user)

def with_siae_stats(self):
return self.annotate(siae_count_annotated=Count("siaes", distinct=True))


class FavoriteList(models.Model):
name = models.CharField(verbose_name="Nom", max_length=255)
Expand Down
32 changes: 14 additions & 18 deletions lemarche/favorites/tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.test import TestCase

from lemarche.favorites.factories import FavoriteListFactory
from lemarche.favorites.models import FavoriteList
from lemarche.siaes.factories import SiaeFactory
from lemarche.siaes.models import Siae
from lemarche.users.factories import UserFactory
Expand Down Expand Up @@ -42,21 +43,16 @@ def test_favorite_list_item_ordering(self):
# -created_at ordering (added last shown first)
self.assertEqual(favorite_list.favoriteitem_set.first().siae, self.siae_1)

def test_siae_annotate_with_user_favorite_list_count(self):
favorite_list_1 = FavoriteListFactory(user=self.user)
favorite_list_1.siaes.add(self.siae_1)
favorite_list_2 = FavoriteListFactory(user=self.user)
favorite_list_2.siaes.add(self.siae_1)
qs = Siae.objects.annotate_with_user_favorite_list_count(self.user)
self.assertEqual(qs.get(id=self.siae_1.id).in_user_favorite_list_count, 2)
self.assertEqual(qs.get(id=self.siae_2.id).in_user_favorite_list_count, 0)

def test_siae_annotate_with_user_favorite_list_ids(self):
favorite_list_1 = FavoriteListFactory(user=self.user)
favorite_list_1.siaes.add(self.siae_1)
favorite_list_2 = FavoriteListFactory(user=self.user)
favorite_list_2.siaes.add(self.siae_1)
qs = Siae.objects.annotate_with_user_favorite_list_ids(self.user)
self.assertEqual(len(qs.get(id=self.siae_1.id).in_user_favorite_list_ids), 2)
self.assertEqual(len(qs.get(id=self.siae_2.id).in_user_favorite_list_ids), 0)
self.assertEqual(qs.get(id=self.siae_1.id).in_user_favorite_list_ids[0], favorite_list_1.id)
def test_with_siae_stats(self):
favorite_list = FavoriteListFactory(user=self.user)
favorite_list_with_siaes = FavoriteListFactory(user=self.user, siaes=[self.siae_1, self.siae_2])
favorite_list_queryset = FavoriteList.objects.with_siae_stats()
self.assertEqual(favorite_list_queryset.get(id=favorite_list.id).siae_count_annotated, 0)
self.assertEqual(favorite_list_queryset.get(id=favorite_list_with_siaes.id).siae_count_annotated, 2)

def test_siae_with_in_user_favorite_list_stats(self):
FavoriteListFactory(user=self.user, siaes=[self.siae_1])
FavoriteListFactory(user=self.user, siaes=[self.siae_1])
siae_queryset = Siae.objects.with_in_user_favorite_list_stats(self.user)
self.assertEqual(siae_queryset.get(id=self.siae_1.id).in_user_favorite_list_count_annotated, 2)
self.assertEqual(siae_queryset.get(id=self.siae_2.id).in_user_favorite_list_count_annotated, 0)
Loading

0 comments on commit f8db4a8

Please sign in to comment.