Django plugin for geolocation info
Reason this release was yanked:
no longer supported
Project description
GeoAuth Plugin Documentation
📌 Overview
GeoAuth is a Django plugin that provides authentication and user-related utilities with geo-location support. It allows users to:
1️⃣ Retrieve their website visitors' IP address.
2️⃣ Fetch device information (browser, OS, etc.).
3️⃣ Obtain location data (country, city, region, latitude, longitude).
4️⃣ Get country details (languages, timezone, currency, etc.).
5️⃣ Restrict user registration based on allowed countries.
🚀 Installation
Using pip
pip install geo-auth
Using Source Code
git clone https://github.com/shoileazeez/drf_geodata.git
cd geo_auth
pip install -r requirements.txt
⚙️ Setup & Configuration
1️⃣ Add to Installed Apps
Modify settings.py:
INSTALLED_APPS = [
# Other apps...
'geo_auth',
]
2️⃣ Run Migrations
python manage.py migrate
3️⃣ Configure Middleware (Optional)
If you want automatic geo-data retrieval, add the middleware in settings.py:
MIDDLEWARE = [
# Other middleware...
'geo_auth.middleware.GeoAuthMiddleware',
]
4️⃣ Enable Plugin URLs
Users should add your plugin’s URLs in their urls.py:
from django.urls import path, include
urlpatterns = [
# Other URLs...
path('geo_auth/', include('geo_auth.urls')), # Enable Goe Auth Plugin API
]
🔑 Token Configuration
-
Retrieve the database token from IP2Location Lite after registration.
-
Add the token to the environment variables:
export TOKEN="your_api_token_here"
-
Modify
settings.pyto retrieve the token dynamically:import os TOKEN = os.getenv("TOKEN")
🌍 GeoNames Username Configuration
- Register for a free account at GeoNames.
- Use the same username you registered with and configure it as an environment variable:
- Modify
settings.pyto retrieve the username dynamically:import os GEONAMES_USERNAME = os.getenv("GEONAMES_USERNAME")
🔌 How to Use the Geo Plugin
🚀 Middleware Usage Options
Option 1: Automatic Retrieval
Middleware automatically attaches geo-data to each request.
from rest_framework.decorators import api_view
from rest_framework.response import Response
def example_view(request):
ip_address = getattr(request, "ip_address", "Unknown")
currency = request.currency
location_data = request.location_data
country_info = request.country_info
device_info = request.device_info
return Response({
"client_ip": ip_address,
"location_data": {
"location": location_data,
"country_info": country_info,
"currency": currency
},
"device_info": device_info,
})
✅ Best for: Users who want automatic access to all geo-data in their views.
Option 2: API Views with Middleware
Using the middleware with dedicated API views for specific geo-data:
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(["GET"])
def get_client_ip_auto(request):
ip_address = getattr(request, "ip_address", "Unknown")
currency = request.currency
location_data = request.location_data
country_info = request.country_info
device_info = request.device_info
return Response({
"client_ip": ip_address,
"location_data": {
"location": location_data,
"country_info": country_info,
"currency": currency
},
"device_info": device_info,
})
@api_view(["GET"])
def get_client_location_from_ip(request):
ip_address = request.ip_address
return Response({
"client_ip": ip_address,
})
@api_view(["GET"])
def get_client_device_info(request):
device_info = request.device_info
return Response({
"device_info": device_info,
})
✅ Best for: Users who want dedicated endpoints for retrieving specific geo-data while still using the middleware.
🛠️ Utility Functions Usage
Option 3: Direct Function Calls
If you prefer calling functions manually, you can import and use utility functions:
from geo_auth.utils import get_client_ip, get_device_info, get_location_data
from django.http import JsonResponse
def example_view(request):
data = {
"ip": get_client_ip(request),
"device": get_device_info(request),
"location": get_location_data(request),
}
return JsonResponse(data)
✅ Best for: Users who only need geo-data in specific views and prefer not to use middleware.
🔗 API Endpoints Usage
Option 4: Using Pre-configured API Endpoints
Access geo-data directly through provided URLs after including the plugin's URLs in your project.
# In your main urls.py
from django.urls import path, include
urlpatterns = [
# Other URLs...
path('geo_auth/', include('geo_auth.urls')),
]
Available endpoints:
GET /geo_auth/ip/
# Returns the client's IP address
# Example response: {"client_ip": "198.51.100.42"}
GET /geo_auth/device/
# Returns detailed information about the client's device
# Example response: {"device_info": {"browser": "Chrome", "os": "Windows", "device": "Desktop"}}
GET /geo_auth/location/
# Returns comprehensive location data based on the client's IP
# Example response: {"location_data": {"city": "New York", "country": "United States", "latitude": 40.7128, "longitude": -74.0060}}
✅ Best for: Projects that need quick access to geo-data without writing custom views.
Option 5: Using Hosted API Service
For users who prefer not to install the plugin, you can use our hosted API service to get the same geo-data with simple HTTP requests:
GET https://api.geoauth.example.com/ip/
GET https://api.geoauth.example.com/device/
GET https://api.geoauth.example.com/location/
Example code to access the hosted API:
1. Python - Requests Library
import requests
# Get location data
response = requests.get('https://api.geoauth.example.com/location/')
data = response.json()
print(data)
2. Python - Standard Library (urllib)
import json
import urllib.request
# Get device info
with urllib.request.urlopen('https://api.geoauth.example.com/device/') as response:
data = json.loads(response.read().decode())
print(data)
3. Python - AIOHTTP (Async)
import aiohttp
import asyncio
async def get_client_ip():
async with aiohttp.ClientSession() as session:
async with session.get('https://api.geoauth.example.com/ip/') as response:
data = await response.json()
return data
# Usage
ip_data = asyncio.run(get_client_ip())
print(ip_data)
4. Python - Django Integration
from django.conf import settings
import requests
def get_geo_info(request):
# Using in Django view
response = requests.get('https://api.geoauth.example.com/location/')
return response.json()
5. Python - Flask Integration
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
@app.route('/user-location')
def user_location():
# Forward client info to GeoAuth API
response = requests.get('https://api.geoauth.example.com/location/')
return jsonify(response.json())
✅ Best for: Users who need geo-data without installing the plugin or for cross-platform applications.
🔐 User Registration with Geo Restriction
📌 Overview
GeoAuth plugin provides country-based registration restrictions, allowing you to control which countries can register users on your platform.
⚙️ Configuration
Add allowed countries to your settings.py:
# settings.py
ALLOWED_COUNTRIES = ["US", "CA", "UK", "AU"] # Country codes or names
🔄 Default Serializer
The plugin includes a default UserSerializer that handles country validation. You can find the default UserSerializer in geo_auth/serializers.py:
from rest_framework import serializers
from django.contrib.auth.models import User
from rest_framework.validators import ValidationError
from django.conf import settings
from .utility import get_location_from_ip, get_client_ip
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
confirm_password = serializers.CharField(write_only=True)
country = serializers.CharField(read_only=True)
class Meta:
model = User
fields = ["username", "email", "password", "confirm_password", "country"]
extra_kwargs = {"password": {"write_only": True}}
def validate_email(self, value):
"""handle email validation """
if User.objects.filter(email=value).exists():
raise serializers.ValidationError("This email address is already in use.")
return value
def validate(self, data):
""" handle country and password validation """
request = self.context.get("request")
if not request:
raise ValidationError({"error": ["Request object is missing."]})
# get ip address from request
ip_address = getattr(request, "ip_address", None)
location_data = get_location_from_ip(ip_address)
allowed_countries = settings.ALLOWED_COUNTRIES
country_name = location_data.get("country", "")
country_code = location_data.get("country_code")
allowed_countries_lower = [c.lower() for c in allowed_countries]
data["country"] = {
"name": country_name.title(),
"code": country_code.upper()
}
# Ensure the country is allowed
if country_code not in allowed_countries and country_name not in allowed_countries_lower:
raise serializers.ValidationError({
"error": "Registration from this country is not allowed.",
"country": data["country"]
})
if len(data['password']) < 8:
raise ValidationError("Password must be at least eight characters long.")
if data['confirm_password'] != data['password']:
raise ValidationError("Confirm password and password must match.")
return data
def create(self, validated_data):
"""
create the user without saving the confirm_password and the country if not in the model instance
"""
validated_data.pop("confirm_password", None)
validated_data.pop("country", None)
user = User.objects.create_user(**validated_data)
return user
🖥️ Default Registration View
The plugin includes a ready-to-use view for user registration:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class UserRegistrationView(APIView):
def post(self, request):
# Pass the request object in the context to the serializer
serializer = UserSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
# Save the user if validation passes
serializer.save()
return Response({
"message": "User registered successfully",
"user": serializer.data, # This includes the 'country' field
"country": serializer.validated_data.get("country", "UNKNOWN")
}, status=status.HTTP_201_CREATED)
# Return validation errors if the data is invalid
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
🛠️ Customization Options
✅ Override the Serializer
User can extend the default serializer to add custom fields or validation:
from geo_auth.serializers import UserSerializer
class CustomUserRegistrationSerializer(UserSerializer):
phone_number = serializers.CharField(max_length=15, required=True)
class Meta(UserSerializer.Meta):
fields = UserSerializer.Meta.fields + ["phone_number"]
# Add additional validation if needed
def validate_phone_number(self, value):
if not value.startswith('+'):
raise serializers.ValidationError("Phone number must include country code")
return value
✅ Override the View
User can customize the registration view:
from geo_auth.views import UserRegistrationView
from .serializers import CustomUserRegistrationSerializer
class CustomRegisterView(UserRegistrationView):
def post(self, request):
serializer = CustomUserRegistrationSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
user = serializer.save()
# Additional custom logic here
return Response({
"message": "User registered with custom logic",
"user": serializer.data,
"country": serializer.validated_data.get("country")
}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
📡 API Usage
Registration Endpoint
POST /geo-auth/register/
Request Body
{
"username": "john_doe",
"email": "john@example.com",
"password": "SecurePass123!",
"confirm_password": "SecurePass123!"
}
Successful Response (201 Created)
{
"message": "User registered successfully",
"user": {
"username": "john_doe",
"email": "john@example.com",
"country": {
"name": "United States",
"code": "US"
}
}
}
Error Response (400 Bad Request)
{
"error": "Registration from this country is not allowed.",
"country": {
"name": "Restricted Country",
"code": "RC"
}
}
Password Validation Error
{
"non_field_errors": ["Password must be at least eight characters long."]
}
Email Already Exists Error
{
"email": ["This email address is already in use."]
}
Certainly! Here’s the license and contribution sections for your documentation:
📝 License
GeoAuth is licensed under the MIT License. See the LICENSE file for more details.
🤝 Contributing
We welcome contributions to the GeoAuth plugin! If you'd like to contribute, please follow these steps:
- Fork the repository on GitHub.
- Clone your fork to your local machine.
git clone https://github.com/shoileazeez/drf_geodata.git cd geo_auth
- Create a new branch for your changes.
git checkout -b feature/your-feature
- Make your changes and commit them.
git commit -m "Add new feature or fix"
- Push your changes to your fork.
git push origin feature/your-feature
- Open a pull request with a description of your changes.
Please ensure your code adheres to the project's style guidelines, and add tests where appropriate. We will review your pull request and merge it once it's ready.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file geo_auth-1.0.4.tar.gz.
File metadata
- Download URL: geo_auth-1.0.4.tar.gz
- Upload date:
- Size: 26.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3f1470cba1acf005972b1edbbdafe2136e7416ef77ee8e31f98637128f20943
|
|
| MD5 |
0ef6f8e1131eaa019638cd5736ea8ad6
|
|
| BLAKE2b-256 |
11ad56b1d2dcbd041f0cf1e4db7fe13feed1683a4d264ad02b0415a053a44afe
|
File details
Details for the file geo_auth-1.0.4-py3-none-any.whl.
File metadata
- Download URL: geo_auth-1.0.4-py3-none-any.whl
- Upload date:
- Size: 26.5 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb1ecd3d6acf5029b1c0d5d8dd4971fa23420a5c6abf6b5dc088356cf1f60429
|
|
| MD5 |
5f9f3108023c75b42c0242b6b4d04e56
|
|
| BLAKE2b-256 |
e594905383448c6db03ae38d5fbce78671c2282d0c3108659dfe9a8692025dc5
|