Skip to main content

A Python package containing Zambian provinces, cities, and constituencies data

Project description

Zambia Geo

A Python package containing Zambian provinces and cities data.

Features

  • List all Zambian provinces
  • Get cities for each province
  • Search for cities
  • Validate province and city names

New in v0.2.0: Constituencies

You can now fetch constituencies for each province or district:

    from zambia_geo import get_constituencies

Get constituencies for a specific province

constituencies = get_constituencies("Southern") for c in constituencies: print(c.name)

Install in Development Mode Locally

  1. Create a virtual environment:

     python -m venv venv
     source venv/bin/activate  # On Windows: venv\Scripts\activate
    
  2. Install the package in development mode:

     git clone https://github.com/sangwani-coder/zambia_geo.git
     cd zambia_geo
     pip install -e .
    
  3. Run Tests

     python3 -m pytest tests/
    

Alternative Installation Methods

Installation in a Project - Force Install

pip install --force-reinstall git+https://github.com/sangwani-coder/zambia_geo.git

Download the ZIP and install

wget https://github.com/sangwani-coder/zambia_geo/archive/main.zip
pip install main.zip

Now you can import and use the package in your Python code:

from zambia_geo import get_all_provinces, get_province_cities
# Get all provinces
provinces = get_all_provinces()
for province in provinces:
    print(province.name, province.capital)

# Get cities in a province
cities = get_province_cities("Lusaka")
for city in cities:
    print(city.name, city.population)

Usage in Django

To use zambia_geo package in Django model choice fields, you'll need to create choices tuples from the package's data. Here's how you can implement this:

Example Django Model Usage

from django.db import models
from zambia_geo.utils import get_province_choices, get_city_choices

class UserProfile(models.Model):
    # Province field
    province = models.CharField(
        max_length=50,
        choices=get_province_choices(),
        blank=True,
        null=True
    )
    
    # City field that depends on province
    city = models.CharField(
        max_length=50,
        choices=[],
        blank=True,
        null=True
    )
    
    class Meta:
        verbose_name = "User Profile"
        verbose_name_plural = "User Profiles"
    
    def __str__(self):
        return f"{self.province} - {self.city}"

Dynamic City Choices Based on Province (Forms)

To make the city choices dynamic based on the selected province, you'll need to use JavaScript or Django's form facilities:

Step 1: Using Django Forms with JavaScript:

# forms.py
from django import forms
from .models import UserProfile
from zambia_geo.utils import get_province_choices, get_city_choices

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['province', 'city']
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['province'].choices = [('', 'Select Province')] + get_province_choices()
        self.fields['city'].choices = [('', 'Select City')]
        
        # Set initial city choices if province is already selected
        if self.instance and self.instance.province:
            self.fields['city'].choices = [('', 'Select City')] + get_city_choices(self.instance.province)

Step 2: Create a View to handle Ajax Request

# views.py
from django.http import JsonResponse
from zambia_geo.utils import get_city_choices

def load_cities(request):
    province = request.GET.get('province')
    if province:
        cities = get_city_choices(province)
        return JsonResponse({'cities': cities})
    return JsonResponse({'cities': []})

Add URL Patten

# urls.py
from django.urls import path
from .views import load_cities

urlpatterns = [
    path('load-cities/', load_cities, name='load_cities'),
    # other paths...
]

In your template

# admin.py
<!-- Include jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<form method="post" id="profileForm">
    {% csrf_token %}
    
    <div class="form-group">
        {{ form.province.label_tag }}
        {{ form.province }}
    </div>
    
    <div class="form-group">
        {{ form.city.label_tag }}
        {{ form.city }}
    </div>
    
    <button type="submit" class="btn btn-primary">Save</button>
</form>

<script>
$(document).ready(function() {
    // When province changes
    $('#id_province').change(function() {
        var provinceId = $(this).val();
        var url = "{% url 'load_cities' %}";
        
        // Clear and disable city dropdown
        $('#id_city').html('<option value="">Select City</option>');
        
        if (provinceId) {
            // Fetch cities for selected province
            $.ajax({
                url: url,
                data: {
                    'province': provinceId
                },
                success: function(data) {
                    // Populate city dropdown
                    var options = '<option value="">Select City</option>';
                    $.each(data.cities, function(index, city) {
                        options += '<option value="' + city[0] + '">' + city[1] + '</option>';
                    });
                    $('#id_city').html(options);
                }
            });
        }
    });
});
</script>

Update your view to Handle your Form

# views.py
from django.shortcuts import render, redirect
from .forms import UserProfileForm

def profile_view(request):
    if request.method == 'POST':
        form = UserProfileForm(request.POST, instance=request.user.profile)
        if form.is_valid():
            form.save()
            return redirect('success_url')
    else:
        form = UserProfileForm(instance=request.user.profile)
    
    return render(request, 'profile_form.html', {'form': form})

Usage in Flask

  flask_zambia_app/
  ├── app.py
  ├── templates/
  │   └── index.html
  └── requirements.txt

Flask Application Code:

  # app.py
  from flask import Flask, render_template, request, jsonify
  from zambia_geo.utils import get_province_choices, get_city_choices
  
  app = Flask(__name__)
  
  @app.route('/', methods=['GET', 'POST'])
  def index():
      if request.method == 'POST':
          # Process form submission
          province = request.form.get('province')
          city = request.form.get('city')
          return f"Selected: {province} Province, {city} City"
      
      # GET request - show the form
      provinces = get_province_choices()
      return render_template('index.html', provinces=provinces)
  
  @app.route('/get_cities')
  def get_cities():
      province = request.args.get('province')
      if province:
          cities = get_city_choices(province)
          return jsonify({'cities': cities})
      return jsonify({'cities': []})
  
  if __name__ == '__main__':
      app.run(debug=True)

Template File:

  <!-- index.html -->
  <!DOCTYPE html>
  <html>
  <head>
      <title>Zambia Provinces and Cities</title>
      <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
      <style>
          .form-group { margin-bottom: 15px; }
          select { padding: 8px; width: 300px; }
      </style>
  </head>
  <body>
      <h1>Select Location in Zambia</h1>
      
      <form method="POST">
          <div class="form-group">
              <label for="province">Province:</label>
              <select id="province" name="province" required>
                  <option value="">Select Province</option>
                  {% for code, name in provinces %}
                      <option value="{{ code }}">{{ name }}</option>
                  {% endfor %}
              </select>
          </div>
          
          <div class="form-group">
              <label for="city">City:</label>
              <select id="city" name="city" required disabled>
                  <option value="">Select City (choose province first)</option>
              </select>
          </div>
          
          <button type="submit">Submit</button>
      </form>
  
      <script>
      $(document).ready(function() {
          $('#province').change(function() {
              var province = $(this).val();
              var $citySelect = $('#city');
              
              $citySelect.empty().prop('disabled', true);
              
              if (province) {
                  $citySelect.append('<option value="">Loading cities...</option>');
                  
                  $.getJSON('/get_cities', {province: province}, function(data) {
                      $citySelect.empty().append('<option value="">Select City</option>');
                      
                      $.each(data.cities, function(index, city) {
                          $citySelect.append(
                              $('<option>', {
                                  value: city[0],
                                  text: city[1]
                              })
                          );
                      });
                      
                      $citySelect.prop('disabled', false);
                  });
              }
          });
      });
      </script>
  </body>
  </html>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zambia_geo-0.2.0.tar.gz (12.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zambia_geo-0.2.0-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file zambia_geo-0.2.0.tar.gz.

File metadata

  • Download URL: zambia_geo-0.2.0.tar.gz
  • Upload date:
  • Size: 12.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for zambia_geo-0.2.0.tar.gz
Algorithm Hash digest
SHA256 97509803a0e324c1cdcf800fb823762b41f6329ea48d6d138486fc559d38fb9d
MD5 a95a37b55ea434cf0d0665f3aad131bb
BLAKE2b-256 4d33a39207552cae1f815abfd24bffb0a451103675effd1eb73fedb6d4a02753

See more details on using hashes here.

File details

Details for the file zambia_geo-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: zambia_geo-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 10.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for zambia_geo-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 772d3d4030b12483987d08a62538978a856b674bb7d2b509d32b5f325eada878
MD5 b1202ff6951a6e52e756cdafd310826a
BLAKE2b-256 ea41096f2bb46cb7181a5eba9c4761c109650cc061f7029fb7926b8382cce686

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page