1from django.apps import apps 2from django.db.models import Case, IntegerField, Q, When 3 4 5MATCH_HOSTNAME_PORT = 0 6MATCH_HOSTNAME_DEFAULT = 1 7MATCH_DEFAULT = 2 8MATCH_HOSTNAME = 3 9 10 11def get_site_for_hostname(hostname, port): 12 """Return the wagtailcore.Site object for the given hostname and port.""" 13 Site = apps.get_model('wagtailcore.Site') 14 15 sites = list(Site.objects.annotate(match=Case( 16 # annotate the results by best choice descending 17 18 # put exact hostname+port match first 19 When(hostname=hostname, port=port, then=MATCH_HOSTNAME_PORT), 20 21 # then put hostname+default (better than just hostname or just default) 22 When(hostname=hostname, is_default_site=True, then=MATCH_HOSTNAME_DEFAULT), 23 24 # then match default with different hostname. there is only ever 25 # one default, so order it above (possibly multiple) hostname 26 # matches so we can use sites[0] below to access it 27 When(is_default_site=True, then=MATCH_DEFAULT), 28 29 # because of the filter below, if it's not default then its a hostname match 30 default=MATCH_HOSTNAME, 31 32 output_field=IntegerField(), 33 )).filter(Q(hostname=hostname) | Q(is_default_site=True)).order_by( 34 'match' 35 ).select_related( 36 'root_page' 37 )) 38 39 if sites: 40 # if theres a unique match or hostname (with port or default) match 41 if len(sites) == 1 or sites[0].match in (MATCH_HOSTNAME_PORT, MATCH_HOSTNAME_DEFAULT): 42 return sites[0] 43 44 # if there is a default match with a different hostname, see if 45 # there are many hostname matches. if only 1 then use that instead 46 # otherwise we use the default 47 if sites[0].match == MATCH_DEFAULT: 48 return sites[len(sites) == 2] 49 50 raise Site.DoesNotExist() 51