77from django .contrib .admin import StackedInline as BaseStackedInline
88from django .contrib .admin import TabularInline as BaseTabularInline
99from django .contrib .admin import display , helpers
10- from django .contrib .admin .utils import lookup_field
10+ from django .contrib .admin .utils import lookup_field , quote
1111from django .contrib .admin .widgets import RelatedFieldWidgetWrapper
1212from django .core .exceptions import ObjectDoesNotExist
1313from django .db import models
3333from django .shortcuts import redirect
3434from django .template .defaultfilters import linebreaksbr
3535from django .template .response import TemplateResponse
36- from django .urls import URLPattern , path , reverse
36+ from django .urls import NoReverseMatch , URLPattern , path , reverse
3737from django .utils .html import conditional_escape , format_html
3838from django .utils .module_loading import import_string
3939from django .utils .safestring import SafeText , mark_safe
@@ -220,6 +220,22 @@ def contents(self) -> str:
220220 contents = self ._preprocess_field (contents )
221221 return contents
222222
223+ def get_admin_url (self , remote_field , remote_obj ):
224+ url_name = f"admin:{ remote_field .model ._meta .app_label } _{ remote_field .model ._meta .model_name } _change"
225+ try :
226+ url = reverse (
227+ url_name ,
228+ args = [quote (remote_obj .pk )],
229+ current_app = self .model_admin .admin_site .name ,
230+ )
231+ return format_html (
232+ '<a href="{}" class="text-primary-600 underline">{}</a>' ,
233+ url ,
234+ remote_obj ,
235+ )
236+ except NoReverseMatch :
237+ return str (remote_obj )
238+
223239 def _get_contents (self ) -> str :
224240 from django .contrib .admin .templatetags .admin_list import _boolean_icon
225241
@@ -239,6 +255,7 @@ def _get_contents(self) -> str:
239255 # ReadOnlyPasswordHashWidget.
240256 if getattr (widget , "read_only" , False ):
241257 return widget .render (field , value )
258+
242259 if f is None :
243260 if getattr (attr , "boolean" , False ):
244261 result_repr = _boolean_icon (value )
@@ -255,6 +272,12 @@ def _get_contents(self) -> str:
255272 and value is not None
256273 ):
257274 result_repr = self .get_admin_url (f .remote_field , value )
275+ elif isinstance (f , models .URLField ):
276+ return format_html (
277+ '<a href="{}" class="text-primary-600 underline">{}</a>' ,
278+ value ,
279+ value ,
280+ )
258281 else :
259282 result_repr = display_for_field (value , f , self .empty_value_display )
260283 return conditional_escape (result_repr )
0 commit comments