Allow to customize user display name and URL slug
This commit is contained in:
parent
453a7b5616
commit
81fcc080d9
9 changed files with 64 additions and 24 deletions
|
@ -82,4 +82,22 @@ And so on!
|
||||||
|
|
||||||
See also
|
See also
|
||||||
[https://github.com/etalab/cartes.data.gouv.fr](https://github.com/etalab/cartes.data.gouv.fr)
|
[https://github.com/etalab/cartes.data.gouv.fr](https://github.com/etalab/cartes.data.gouv.fr)
|
||||||
for an example of customization.
|
for an example of theme customization.
|
||||||
|
|
||||||
|
|
||||||
|
## Custom user display name
|
||||||
|
|
||||||
|
In some situation, you may want to customize the display name of users, which
|
||||||
|
is by default the username.
|
||||||
|
|
||||||
|
There are three settings you can play with to control that:
|
||||||
|
|
||||||
|
# The display name itself, could be for example "{first_name} {last_name}"
|
||||||
|
USER_DISPLAY_NAME = "{username}"
|
||||||
|
# Which field to search for when autocompleting users (for permissions)
|
||||||
|
# See https://django-agnocomplete.readthedocs.io/en/latest/autocomplete-definition.html#agnocompletemode
|
||||||
|
USER_AUTOCOMPLETE_FIELDS = ["^username"]
|
||||||
|
# Which field to use in the URL, may also be for example "pk" to use the
|
||||||
|
# primary key and not expose the username (which may be private or may change too
|
||||||
|
# often for URL persistance)
|
||||||
|
USER_URL_FIELD = "username"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
|
|
||||||
from agnocomplete.register import register
|
from agnocomplete.register import register
|
||||||
|
@ -10,10 +9,9 @@ from agnocomplete.core import AgnocompleteModel
|
||||||
@register
|
@register
|
||||||
class AutocompleteUser(AgnocompleteModel):
|
class AutocompleteUser(AgnocompleteModel):
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
fields = ['^username']
|
fields = settings.USER_AUTOCOMPLETE_FIELDS
|
||||||
|
|
||||||
def item(self, current_item):
|
def item(self, current_item):
|
||||||
data = super().item(current_item)
|
data = super().item(current_item)
|
||||||
data['url'] = reverse(settings.USER_MAPS_URL,
|
data['url'] = current_item.get_url()
|
||||||
args=(current_item.get_username(), ))
|
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
@ -12,6 +13,29 @@ from django.core.files.base import File
|
||||||
from .managers import PublicManager
|
from .managers import PublicManager
|
||||||
|
|
||||||
|
|
||||||
|
# Did not find a clean way to do this in Django
|
||||||
|
# - creating a Proxy model would mean replacing get_user_model by this proxy model
|
||||||
|
# in every template
|
||||||
|
# - extending User model woulc mean a non trivial migration
|
||||||
|
def display_name(self):
|
||||||
|
return settings.USER_DISPLAY_NAME.format(**self.__dict__)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_url(self):
|
||||||
|
identifier = getattr(self, settings.USER_URL_FIELD)
|
||||||
|
return reverse(settings.USER_MAPS_URL, kwargs={"identifier": identifier})
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_stars_url(self):
|
||||||
|
identifier = getattr(self, settings.USER_URL_FIELD)
|
||||||
|
return reverse("user_stars", kwargs={"identifier": identifier})
|
||||||
|
|
||||||
|
|
||||||
|
User.add_to_class("__str__", display_name)
|
||||||
|
User.add_to_class("get_url", get_user_url)
|
||||||
|
User.add_to_class("get_stars_url", get_user_stars_url)
|
||||||
|
|
||||||
|
|
||||||
class NamedModel(models.Model):
|
class NamedModel(models.Model):
|
||||||
name = models.CharField(max_length=200, verbose_name=_("name"))
|
name = models.CharField(max_length=200, verbose_name=_("name"))
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,11 @@ MIDDLEWARE = (
|
||||||
# Set to True if login into django account should be possible. Default is to
|
# Set to True if login into django account should be possible. Default is to
|
||||||
# only use OAuth flow.
|
# only use OAuth flow.
|
||||||
ENABLE_ACCOUNT_LOGIN = env.bool("ENABLE_ACCOUNT_LOGIN", default=False)
|
ENABLE_ACCOUNT_LOGIN = env.bool("ENABLE_ACCOUNT_LOGIN", default=False)
|
||||||
|
USER_DISPLAY_NAME = "{username}"
|
||||||
|
# For use by Agnocomplete
|
||||||
|
# See https://django-agnocomplete.readthedocs.io/en/latest/autocomplete-definition.html#agnocompletemode
|
||||||
|
USER_AUTOCOMPLETE_FIELDS = ["^username"]
|
||||||
|
USER_URL_FIELD = "username"
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Miscellaneous project settings
|
# Miscellaneous project settings
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
window.opener.umap_proceed();
|
window.opener.umap_proceed();
|
||||||
} else {
|
} else {
|
||||||
// Trade off as Twitter does not allow us to access window.opener
|
// Trade off as Twitter does not allow us to access window.opener
|
||||||
window.location.href = '{% url "user_maps" request.user.username %}'
|
window.location.href = '{{ request.user.get_url }}'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<hr />
|
<hr />
|
||||||
<div class="col wide">
|
<div class="col wide">
|
||||||
{% map_fragment map_inst prefix=prefix page=request.GET.p %}
|
{% map_fragment map_inst prefix=prefix page=request.GET.p %}
|
||||||
<div class="legend"><a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a>{% if map_inst.owner %} <em>{% trans "by" %} <a href="{% url 'user_maps' map_inst.owner.username %}">{{ map_inst.owner }}</a></em>{% endif %}</div>
|
<div class="legend"><a href="{{ map_inst.get_absolute_url }}">{{ map_inst.name }}</a>{% if map_inst.owner %} <em>{% trans "by" %} <a href="{{ map_inst.owner.get_url }}">{{ map_inst.owner }}</a></em>{% endif %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if maps.has_next %}
|
{% if maps.has_next %}
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<section>
|
<section>
|
||||||
<ul>
|
<ul>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<li><a href="{% url 'user_maps' user.username %}">{% trans "My maps" %} ({{ user }})</a></li>
|
<li><a href="{{ user.get_url }}">{% trans "My maps" %} ({{ user }})</a></li>
|
||||||
<li><a href="{% url 'user_stars' user.username %}">{% trans "Starred maps" %}</a></li>
|
<li><a href="{{ user.get_stars_url %}">{% trans "Starred maps" %}</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a href="{% url 'login' %}" class="login">{% trans "Log in" %} / {% trans "Sign in" %}</a></li>
|
<li><a href="{% url 'login' %}" class="login">{% trans "Log in" %} / {% trans "Sign in" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -157,8 +157,8 @@ urlpatterns += i18n_patterns(
|
||||||
),
|
),
|
||||||
re_path(r"^search/$", views.search, name="search"),
|
re_path(r"^search/$", views.search, name="search"),
|
||||||
re_path(r"^about/$", views.about, name="about"),
|
re_path(r"^about/$", views.about, name="about"),
|
||||||
re_path(r"^user/(?P<username>.+)/stars/$", views.user_stars, name="user_stars"),
|
re_path(r"^user/(?P<identifier>.+)/stars/$", views.user_stars, name="user_stars"),
|
||||||
re_path(r"^user/(?P<username>.+)/$", views.user_maps, name="user_maps"),
|
re_path(r"^user/(?P<identifier>.+)/$", views.user_maps, name="user_maps"),
|
||||||
re_path(r"", include(i18n_urls)),
|
re_path(r"", include(i18n_urls)),
|
||||||
)
|
)
|
||||||
urlpatterns += (path("stats/", cache_page(60 * 60)(views.stats), name="stats"),)
|
urlpatterns += (path("stats/", cache_page(60 * 60)(views.stats), name="stats"),)
|
||||||
|
|
|
@ -154,8 +154,8 @@ about = About.as_view()
|
||||||
|
|
||||||
class UserMaps(DetailView, PaginatorMixin):
|
class UserMaps(DetailView, PaginatorMixin):
|
||||||
model = User
|
model = User
|
||||||
slug_url_kwarg = "username"
|
slug_url_kwarg = "identifier"
|
||||||
slug_field = "username"
|
slug_field = settings.USER_URL_FIELD
|
||||||
list_template_name = "umap/map_list.html"
|
list_template_name = "umap/map_list.html"
|
||||||
context_object_name = "current_user"
|
context_object_name = "current_user"
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ class MapsShowCase(View):
|
||||||
description = "{description}\n{by} [[{url}|{name}]]".format(
|
description = "{description}\n{by} [[{url}|{name}]]".format(
|
||||||
description=description,
|
description=description,
|
||||||
by=_("by"),
|
by=_("by"),
|
||||||
url=reverse("user_maps", kwargs={"username": m.owner.username}),
|
url=m.owner.get_url(),
|
||||||
name=m.owner,
|
name=m.owner,
|
||||||
)
|
)
|
||||||
description = "{}\n[[{}|{}]]".format(
|
description = "{}\n[[{}|{}]]".format(
|
||||||
|
@ -418,8 +418,8 @@ class MapDetailMixin:
|
||||||
if not user.is_anonymous:
|
if not user.is_anonymous:
|
||||||
properties["user"] = {
|
properties["user"] = {
|
||||||
"id": user.pk,
|
"id": user.pk,
|
||||||
"name": user.get_username(),
|
"name": str(user),
|
||||||
"url": reverse(settings.USER_MAPS_URL, args=(user.get_username(),)),
|
"url": user.get_url(),
|
||||||
}
|
}
|
||||||
map_settings = self.get_geojson()
|
map_settings = self.get_geojson()
|
||||||
if "properties" not in map_settings:
|
if "properties" not in map_settings:
|
||||||
|
@ -465,16 +465,11 @@ class PermissionsMixin:
|
||||||
if self.object.owner:
|
if self.object.owner:
|
||||||
permissions["owner"] = {
|
permissions["owner"] = {
|
||||||
"id": self.object.owner.pk,
|
"id": self.object.owner.pk,
|
||||||
"name": self.object.owner.get_username(),
|
"name": str(self.object.owner),
|
||||||
"url": reverse(
|
"url": self.object.owner.get_url(),
|
||||||
settings.USER_MAPS_URL, args=(self.object.owner.get_username(),)
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
permissions["editors"] = [
|
permissions["editors"] = [
|
||||||
{
|
{"id": editor.pk, "name": str(editor)}
|
||||||
"id": editor.pk,
|
|
||||||
"name": editor.get_username(),
|
|
||||||
}
|
|
||||||
for editor in self.object.editors.all()
|
for editor in self.object.editors.all()
|
||||||
]
|
]
|
||||||
if not self.object.owner and self.object.is_anonymous_owner(self.request):
|
if not self.object.owner and self.object.is_anonymous_owner(self.request):
|
||||||
|
|
Loading…
Reference in a new issue