From 01fd04756800beb8838853e058b3dacf02db0641 Mon Sep 17 00:00:00 2001 From: Matteo Rosati Date: Wed, 11 Feb 2026 12:26:54 +0100 Subject: [PATCH] display name uniqueness --- db.sqlite3 | Bin 172032 -> 180224 bytes .../0002_userprofile_display_name_unique.py | 15 +++++++++++++++ frontend/models.py | 2 +- frontend/views.py | 8 ++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 frontend/migrations/0002_userprofile_display_name_unique.py diff --git a/db.sqlite3 b/db.sqlite3 index 0b687b420ef8c347a23e203842e7aef7af6f1112..69d08b4fdd584e124beff3ab238cf364e66b0d9c 100644 GIT binary patch delta 4081 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 F;NLCVKIs4e delta 3361 zcmai1eQZfF|iXHLTC#iAs^s4rIdzFTa6PtiHX0G z*db{(Ig}#0ZnTsq)qqxtHtmn8-3FwawYHnsm!`H`L24(hEiE6_I;ORw>a?~hQ@8uB zpMh?Z_J@yu=XdTs@4R#GIX+%oG%ubr9kEsJU>Ih#{$a`Y=#y(Y2)XvLY6H;_+#r&% zp2<7`f?X!i!H=nYMfXyp!^SU-S)UQ=PB0==GVm98173tV_$E9DJHQQjOzHm63o{FXFs<{9v_#&v<$TeHIA*6cS`V1D#xsm!%Tf<87geozT%T9)Kv#}YX zS!5H}fNnC_%5fb?{e@&vUvFDucbLc$6IdDe8$1Y?;8pk;oB}HeVi$OqDl<2f`Z{cP zqVbt@DjQ2hHK&=G^msfGGpUC+H6u|yyQ#TVsK6FGie%!Wxp*QPPfhUE*lt6!vDw*p zIyI|*8`U+NmgfyJuBo8`Y0j_(*ECWs6ProK>3UAVHCD<^%%pP}wh~+IVkDZ3rxNLj zSSmZSpe52J_A+o0&cdTG3SA&6?<&tLPbo7>NLi~?$sftD$*1Lm^1ZTC`b2s|dQN&o z+9TZ|*{jUg%)c}rHs52mnl783HDycz@eA>F@jK$Q*h`M(13_@R3=HzDH>uBuR`RU` z`!<@?E1}i=N*z}XujX3_b_Yyq&#+SpG!tcgw>TG%?NcFCqyBZs$~y_SajU3`AwS=w zV@KGkIzm_thwAx8!UZ;oYChx<0uJgxP(KQK`3AaJP@j0fs@^qZ=U3?Z4~V`%bUWQB zs80`hgy!W$X>H@xg2uksny%wQv5tK(w?*AVP<8`X1zHlEyYk|l$Bb#NtbA=tOkpu)D* ze3gzj6I@BKJ77?!w>7s^5Zus;wItEosRf`Z4(%d1fLNVwtiG_##w$9$xXsoh6Krq6 zTIAZga?~1LArV{SDwcYrcjcx_sx_I3y~V?-UEA%vNyiUtx3`D{H?*>v&zsw{R8Ykw z5Uaa`Q%`Mo@;t$9>pAt6?XA2~$Da{wAb6FJQ&$EZd^0vMVyjOL1six5N3c7f=7LV% z#g_0Xf}0S*Ep6(nLHlm4=3LSt2Cle}FN{7hhZIkk~7eQ#q%XzcX*38(!6roYf>^w ze z*}sWV?@UD0*AlhlO}q+Dc_i)044pr~)1H09%So!+VWKwvyFKesOtA06*VM5q19>GZmF0lzmjwKleG z{=U7vQ^WiAcJJB}3&;Btsrkg@%}p6Uzrc#^xP<`N@Y zMt5$Qjs*J?@#uYhvD9vV$CiQ2V8@Pu@pLqhymxmfn%I}}&E)d&-q7BT;owks#y{?l z_Vw>gjO^>|?hA%eeZijCXt#f7ZZtGM*c}@552VK@BM)x#k1UMcKRDr;2>0j4{P7L` zdwK__=f(!M4y66#JGy*x)13qJU0<2manIK9fG-uEU)Zo~A)5$#Jdydp7GLLNW@>P% zf1ooOo$KydJ=T+%EvLLa;PCmn+I?OAz*?Wr8}QTIBDhEf0>(u0dI6f9+>rSHa(4D~ zrK9aUybQl0W6z)A3cL+}fFhiMXW@JB3>*g)4#OeX4-Y{O(h!F+_}bFu3yt9Bmm4^Q zcpH_=sI1qdv5rbBmE=4Lqkij>y$4rl7z33Gm9i#TiApn-CMrcuasrh+l}0L;KDbo3 zhpS}1QRFwH&l`C5>r6FjLIq_Hs;f0#H53d1?x);t_8@9v{m93hW(ErDkFmbOp=0cF z<$%z`9}tFk>&OUtBwcvt7&}}DeVc{C#^da&!Vh0!P4dHVH*XCD(1Gr3Wb~;Q*xKUO z2X9-U(0@$;zJAYjJrQHz@zT)<<-V!v&Kv>3@=o8B_ZBc#nx@SI1> zdoX5dYP6wN>s?hG(Hb@FR?CoC!dW$r_N7XM8LRzEGvrS$AnY(AxXQp)a%KJqg{%KU z7V~YF>g+jOQDKDl82BfA3LnFVa1GugOV5LdIT0B(K~AOGar6i_aquPse~0(sO|s%e zD7-w(+FfQ6MLkMJve{UgGm{uJWhS1RWwmC&!F2|1z(3$R*>VL6*Tbx_fu1#sIV7^$ zlxq|g8ReY3C~Y<~;yGcFbftt)T%2S#BmD542BG-tID3Z%u~5WQCCCZI-b4wqLh+Gg z2_mvKMYfSQa%zL~030R5h7*e9r~nGiJlles$sdZs<-M%KV4!e1&o-9GJxM}xlsuIp ikk#s|a5>GomW0L6;K{pr4lzv8bcFpF@UCER)xQDYl6-#v diff --git a/frontend/migrations/0002_userprofile_display_name_unique.py b/frontend/migrations/0002_userprofile_display_name_unique.py new file mode 100644 index 0000000..231d0f1 --- /dev/null +++ b/frontend/migrations/0002_userprofile_display_name_unique.py @@ -0,0 +1,15 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("frontend", "0001_userprofile"), + ] + + operations = [ + migrations.AlterField( + model_name="userprofile", + name="display_name", + field=models.CharField(max_length=150, unique=True), + ), + ] diff --git a/frontend/models.py b/frontend/models.py index 8ab97e7..3e559e1 100644 --- a/frontend/models.py +++ b/frontend/models.py @@ -10,7 +10,7 @@ class UserProfile(models.Model): on_delete=models.CASCADE, related_name="profile", ) - display_name = models.CharField(max_length=150) + display_name = models.CharField(max_length=150, unique=True) def __str__(self): return f"{self.display_name} ({self.user.username})" # type: ignore[attr-defined] diff --git a/frontend/views.py b/frontend/views.py index 1977db0..37d9f89 100644 --- a/frontend/views.py +++ b/frontend/views.py @@ -53,6 +53,14 @@ def register(request: HttpRequest) -> HttpResponse: if email and User.objects.filter(username=email).exists(): errors.append("An account with that email already exists.") + if ( + display_name + and UserProfile.objects.filter( # type: ignore[attr-defined] + display_name=display_name + ).exists() + ): + errors.append("That display name is already taken.") + if errors: for error in errors: messages.error(request, error)