mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #35841 -- Restored support for DB-IP databases in GeoIP2.
Thanks Felix Farquharson for the report and Claude Paroz for the
review.
Regression in 40b5b1596f
.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
This commit is contained in:
parent
5873f10177
commit
3fad712a91
@ -34,6 +34,18 @@ else:
|
||||
__all__ += ["GeoIP2", "GeoIP2Exception"]
|
||||
|
||||
|
||||
# These are the values stored in the `database_type` field of the metadata.
|
||||
# See https://maxmind.github.io/MaxMind-DB/#database_type for details.
|
||||
SUPPORTED_DATABASE_TYPES = {
|
||||
"DBIP-City-Lite",
|
||||
"DBIP-Country-Lite",
|
||||
"GeoIP2-City",
|
||||
"GeoIP2-Country",
|
||||
"GeoLite2-City",
|
||||
"GeoLite2-Country",
|
||||
}
|
||||
|
||||
|
||||
class GeoIP2Exception(Exception):
|
||||
pass
|
||||
|
||||
@ -106,7 +118,7 @@ class GeoIP2:
|
||||
)
|
||||
|
||||
database_type = self._metadata.database_type
|
||||
if not database_type.endswith(("City", "Country")):
|
||||
if database_type not in SUPPORTED_DATABASE_TYPES:
|
||||
raise GeoIP2Exception(f"Unable to handle database edition: {database_type}")
|
||||
|
||||
def __del__(self):
|
||||
@ -123,6 +135,14 @@ class GeoIP2:
|
||||
def _metadata(self):
|
||||
return self._reader.metadata()
|
||||
|
||||
@cached_property
|
||||
def is_city(self):
|
||||
return "City" in self._metadata.database_type
|
||||
|
||||
@cached_property
|
||||
def is_country(self):
|
||||
return "Country" in self._metadata.database_type
|
||||
|
||||
def _query(self, query, *, require_city=False):
|
||||
if not isinstance(query, (str, ipaddress.IPv4Address, ipaddress.IPv6Address)):
|
||||
raise TypeError(
|
||||
@ -130,9 +150,7 @@ class GeoIP2:
|
||||
"IPv6Address, not type %s" % type(query).__name__,
|
||||
)
|
||||
|
||||
is_city = self._metadata.database_type.endswith("City")
|
||||
|
||||
if require_city and not is_city:
|
||||
if require_city and not self.is_city:
|
||||
raise GeoIP2Exception(f"Invalid GeoIP city data file: {self._path}")
|
||||
|
||||
try:
|
||||
@ -141,7 +159,7 @@ class GeoIP2:
|
||||
# GeoIP2 only takes IP addresses, so try to resolve a hostname.
|
||||
query = socket.gethostbyname(query)
|
||||
|
||||
function = self._reader.city if is_city else self._reader.country
|
||||
function = self._reader.city if self.is_city else self._reader.country
|
||||
return function(query)
|
||||
|
||||
def city(self, query):
|
||||
|
@ -14,3 +14,6 @@ Bugfixes
|
||||
:class:`~django.core.validators.DomainNameValidator` accepted any input value
|
||||
that contained a valid domain name, rather than only input values that were a
|
||||
valid domain name (:ticket:`35845`).
|
||||
|
||||
* Fixed a regression in Django 5.1 that prevented the use of DB-IP databases
|
||||
with :class:`~django.contrib.gis.geoip2.GeoIP2` (:ticket:`35841`).
|
||||
|
@ -12,3 +12,17 @@ Updates can be found in [this repository][1].
|
||||
|
||||
[0]: https://github.com/maxmind/MaxMind-DB/blob/main/LICENSE-MIT
|
||||
[1]: https://github.com/maxmind/MaxMind-DB/tree/main/test-data
|
||||
|
||||
# DB-IP Lite Test Databases
|
||||
|
||||
The following test databases are provided under [this license][2]:
|
||||
|
||||
- `dbip-city-lite-test.mmdb`
|
||||
- `dbip-country-lite-test.mmdb`
|
||||
|
||||
They have been modified to strip them down to a minimal dataset for testing.
|
||||
|
||||
Updates can be found at [this download page][3] from DB-IP.
|
||||
|
||||
[2]: https://creativecommons.org/licenses/by/4.0/
|
||||
[3]: https://db-ip.com/db/lite.php
|
||||
|
BIN
tests/gis_tests/data/geoip2/dbip-city-lite-test.mmdb
Normal file
BIN
tests/gis_tests/data/geoip2/dbip-city-lite-test.mmdb
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
tests/gis_tests/data/geoip2/dbip-country-lite-test.mmdb
Normal file
BIN
tests/gis_tests/data/geoip2/dbip-country-lite-test.mmdb
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -124,7 +124,8 @@ class GeoLite2Test(SimpleTestCase):
|
||||
|
||||
def test_country(self):
|
||||
g = GeoIP2(city="<invalid>")
|
||||
self.assertIs(g._metadata.database_type.endswith("Country"), True)
|
||||
self.assertIs(g.is_city, False)
|
||||
self.assertIs(g.is_country, True)
|
||||
for query in self.query_values:
|
||||
with self.subTest(query=query):
|
||||
self.assertEqual(g.country(query), self.expected_country)
|
||||
@ -137,7 +138,8 @@ class GeoLite2Test(SimpleTestCase):
|
||||
|
||||
def test_country_using_city_database(self):
|
||||
g = GeoIP2(country="<invalid>")
|
||||
self.assertIs(g._metadata.database_type.endswith("City"), True)
|
||||
self.assertIs(g.is_city, True)
|
||||
self.assertIs(g.is_country, False)
|
||||
for query in self.query_values:
|
||||
with self.subTest(query=query):
|
||||
self.assertEqual(g.country(query), self.expected_country)
|
||||
@ -150,7 +152,8 @@ class GeoLite2Test(SimpleTestCase):
|
||||
|
||||
def test_city(self):
|
||||
g = GeoIP2(country="<invalid>")
|
||||
self.assertIs(g._metadata.database_type.endswith("City"), True)
|
||||
self.assertIs(g.is_city, True)
|
||||
self.assertIs(g.is_country, False)
|
||||
for query in self.query_values:
|
||||
with self.subTest(query=query):
|
||||
self.assertEqual(g.city(query), self.expected_city)
|
||||
@ -224,6 +227,27 @@ class GeoIP2Test(GeoLite2Test):
|
||||
"""Non-free GeoIP2 databases are supported."""
|
||||
|
||||
|
||||
@skipUnless(HAS_GEOIP2, "GeoIP2 is required.")
|
||||
@override_settings(
|
||||
GEOIP_CITY="dbip-city-lite-test.mmdb",
|
||||
GEOIP_COUNTRY="dbip-country-lite-test.mmdb",
|
||||
)
|
||||
class DBIPLiteTest(GeoLite2Test):
|
||||
"""DB-IP Lite databases are supported."""
|
||||
|
||||
expected_city = GeoLite2Test.expected_city | {
|
||||
"accuracy_radius": None,
|
||||
"city": "London (Shadwell)",
|
||||
"latitude": 51.5181,
|
||||
"longitude": -0.0714189,
|
||||
"postal_code": None,
|
||||
"region_code": None,
|
||||
"time_zone": None,
|
||||
# Kept for backward compatibility.
|
||||
"region": None,
|
||||
}
|
||||
|
||||
|
||||
@skipUnless(HAS_GEOIP2, "GeoIP2 is required.")
|
||||
class ErrorTest(SimpleTestCase):
|
||||
def test_missing_path(self):
|
||||
|
Loading…
Reference in New Issue
Block a user