django-postcodes


Namedjango-postcodes JSON
Version 1.0.6 PyPI version JSON
download
home_pagehttps://github.com/Nigel2392/postcodes
SummaryA Django app to manage postcode/home number address forms
upload_time2024-12-05 10:38:57
maintainerNone
docs_urlNone
authorNigel
requires_python>=3.8
licenseGPL-3.0-only
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            postcodes
================

**A dutch postcode lookup app for Django.**

By default we use the free (but rate limited) API from [postcode.go-dev.nl](https://postcode.go-dev.nl/).

You must create an account and get an API key to use this package (in the default configuration).

This API key must be set in the [settings](#settings).

**Features**

* Lookup addresses by postcode and home number
* Customizable form fields
* Customizable API endpoint
* Autofill form fields with the address data
* Validation of form fields when the address is not found
* Validation of form fields when user input was given (regex, min, max.)

Quick start
-----------

1. Install the package via pip:

   ```bash
   pip install django-postcodes
   ```

2. Add 'postcodes' to your INSTALLED_APPS setting like this:

   ```
   INSTALLED_APPS = [
   ...,
      'postcodes',
   ]
   ```
3. Add the postcodes URL to your project's `urls.py`:

   ```python
   path('postcodes/', include('postcodes.urls', namespace='postcodes')),
   ```


## Example usage

First we must define the appropriate form.

This is an example of a form that uses the default API endpoint (custom ones can be defined in the settings):

Every attribute can be customized, except for the postcode and home number fields, which are required for the lookup.

These are hard-coded.

All other elements provided in the `bind` object will be filled in with the data from the API.

```python
class AddressForm(forms.Form):
    # These are required for the lookup
    postcode = forms.CharField(max_length=10, widget=forms.TextInput(attrs={"placeholder": "1234 AB", "class": "postcode", "pattern": "^[0-9]{4}(\s+|)[A-Z]{2}$"}))
    home_number = forms.CharField(max_length=10, widget=forms.TextInput(attrs={"placeholder": "123", "class": "home_number"}))
    
    # Custom fields
    street = forms.CharField(max_length=255, widget=forms.TextInput(attrs={"placeholder": "Main street", "class": "street"}))
    city = forms.CharField(max_length=255, widget=forms.TextInput(attrs={"placeholder": "Amsterdam", "class": "city"}))
    municipality = forms.CharField(max_length=255, widget=forms.TextInput(attrs={"placeholder": "Amsterdam", "class": "municipality"}))
    province = forms.CharField(max_length=255, widget=forms.TextInput(attrs={"placeholder": "Noord-Holland", "class": "province"}))
    build_year = forms.IntegerField(widget=forms.NumberInput(attrs={"placeholder": "1990", "class": "build_year", "pattern": "^[0-9]{4}$", "min": "1900", "max": "2022"}))
    floor_area = forms.DecimalField(widget=forms.NumberInput(attrs={"placeholder": "100", "class": "floor_area", "pattern": "^[0-9]{1,3}$"})) # "pattern": "^[0-9]{1,3}$"
    geo_x = forms.DecimalField(widget=forms.NumberInput(attrs={"placeholder": "52.123456", "class": "geo_x"}))
    geo_y = forms.DecimalField(widget=forms.NumberInput(attrs={"placeholder": "4.123456", "class": "geo_y"}))
    rd_x = forms.DecimalField(widget=forms.NumberInput(attrs={"placeholder": "123456", "class": "rd_x"})) # Rijksdriehoek
    rd_y = forms.DecimalField(widget=forms.NumberInput(attrs={"placeholder": "123456", "class": "rd_y"})) # Rijksdriehoek
```

Then we can define our template

```html
{% extends 'base.html' %}

{% block content %}
   <link rel="stylesheet" href="{% static 'postcodes/css/postcodes.css' %}">
   <script src="{% static 'postcodes/js/postcodes.js' %}" data-api-url="{% url "postcodes:api" %}"></script>

   <form method="post">
       {% csrf_token %}
       {{ form.as_p }}
       <button type="submit">Submit</button>
   </form>

   ...

   <script>
       document.addEventListener('DOMContentLoaded', function() {
           lookupPostcode({
               // Add invalid classes to the input fields when they are invalid
               validate: true,
               bind: {
                   // These are required for the lookup
                    postcode: document.querySelector('#id_postcode'),
                    home_number: document.querySelector('#id_home_number'),

                    // Custom fields returned by the API
                    straat: document.querySelector("#id_street"),
                    woonplaats: document.querySelector("#id_city"),
                    gemeente: document.querySelector("#id_municipality"),
                    provincie: document.querySelector("#id_province"),
                    bouwjaar: document.querySelector("#id_build_year"),
                    vloeroppervlakte: document.querySelector("#id_floor_area"),

                    // Or optionally as a queryselector
                    // If everything is a string - it is safe to omit the DOMContentLoaded eventListener
                    latitude: "#id_geo_x",
                    longitude: "#id_geo_y",
                    rd_x: "#id_rd_x",
                    rd_y: "#id_rd_y",
               },
               success: function(addr) {
                   console.log(addr);
               },
               error: function(error) {
                   console.log(error);
               }
           })
       });
   </script>

{% endblock %}
```

The form will now automatically fill in the address fields when a valid postcode and home number is entered.

If it is invalid or not found, the error callback will be called.

## Settings

### `ADDR_VALIDATOR_API_KEY`

The API key to use for the postcode lookup.

This will be used by the `postcodes.postcode.address_check` function.


### `ADDR_VALIDATOR_API_URL`

The API URL to use for the postcode lookup.

This will be used by the `postcodes.postcode.address_check` function.

It should contain the `{postcode}` and `{home_number}` placeholders.


### `ADDR_VALIDATOR_PARAMETER_FORMAT`

An actual function that formats the parameters for the API URL.

This may not be a path to a function, but the function itself.

Example:

```python
def default_parameter_formatter(**kwargs):
    return "&".join([f"{key}={value}" for key, value in kwargs.items()])
```


### `ADDR_VALIDATOR_ERROR_ATTRIBUTE`

The attribute in the response that contains the error message.

This will be used by the `postcodes.postcode.address_check` function.

AddressValidationError exceptions will return the appropriate error message if the attribute is found.


### `ADDR_VALIDATOR_CACHE_TIMEOUT`

The timeout for the cache in seconds.

This will be used by the `postcodes.postcode.address_check` function.

It is highly recommended to set this to a high number; by default it caches for a week.

The default endpoint is free to use, but has a rate limit.


### `ADDR_VALIDATOR_API_KEY_ATTRIBUTE`

The attribute in the response that contains the API key.

This will be used by the `postcodes.postcode.address_check` function.

It is the header that should be sent with the request.

Defaults to `X-API-Token`.


### `ADDR_VALIDATOR_REQUIRES_AUTH`

Whether the API requires authentication.

This will be used by the internal view to check if the user is authenticated.

If the user is authenticated; the view will return the address data.

This does not matter if you use the `postcodes.postcode.address_check` function.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Nigel2392/postcodes",
    "name": "django-postcodes",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "Nigel",
    "author_email": "nigel@goodadvice.it",
    "download_url": "https://files.pythonhosted.org/packages/26/a6/ea1c4113470c9c8e67b8ff65607c342ebb1bea43ed4d8488c4a029a8edaf/django_postcodes-1.0.6.tar.gz",
    "platform": null,
    "description": "postcodes\r\n================\r\n\r\n**A dutch postcode lookup app for Django.**\r\n\r\nBy default we use the free (but rate limited) API from [postcode.go-dev.nl](https://postcode.go-dev.nl/).\r\n\r\nYou must create an account and get an API key to use this package (in the default configuration).\r\n\r\nThis API key must be set in the [settings](#settings).\r\n\r\n**Features**\r\n\r\n* Lookup addresses by postcode and home number\r\n* Customizable form fields\r\n* Customizable API endpoint\r\n* Autofill form fields with the address data\r\n* Validation of form fields when the address is not found\r\n* Validation of form fields when user input was given (regex, min, max.)\r\n\r\nQuick start\r\n-----------\r\n\r\n1. Install the package via pip:\r\n\r\n   ```bash\r\n   pip install django-postcodes\r\n   ```\r\n\r\n2. Add 'postcodes' to your INSTALLED_APPS setting like this:\r\n\r\n   ```\r\n   INSTALLED_APPS = [\r\n   ...,\r\n      'postcodes',\r\n   ]\r\n   ```\r\n3. Add the postcodes URL to your project's `urls.py`:\r\n\r\n   ```python\r\n   path('postcodes/', include('postcodes.urls', namespace='postcodes')),\r\n   ```\r\n\r\n\r\n## Example usage\r\n\r\nFirst we must define the appropriate form.\r\n\r\nThis is an example of a form that uses the default API endpoint (custom ones can be defined in the settings):\r\n\r\nEvery attribute can be customized, except for the postcode and home number fields, which are required for the lookup.\r\n\r\nThese are hard-coded.\r\n\r\nAll other elements provided in the `bind` object will be filled in with the data from the API.\r\n\r\n```python\r\nclass AddressForm(forms.Form):\r\n    # These are required for the lookup\r\n    postcode = forms.CharField(max_length=10, widget=forms.TextInput(attrs={\"placeholder\": \"1234 AB\", \"class\": \"postcode\", \"pattern\": \"^[0-9]{4}(\\s+|)[A-Z]{2}$\"}))\r\n    home_number = forms.CharField(max_length=10, widget=forms.TextInput(attrs={\"placeholder\": \"123\", \"class\": \"home_number\"}))\r\n    \r\n    # Custom fields\r\n    street = forms.CharField(max_length=255, widget=forms.TextInput(attrs={\"placeholder\": \"Main street\", \"class\": \"street\"}))\r\n    city = forms.CharField(max_length=255, widget=forms.TextInput(attrs={\"placeholder\": \"Amsterdam\", \"class\": \"city\"}))\r\n    municipality = forms.CharField(max_length=255, widget=forms.TextInput(attrs={\"placeholder\": \"Amsterdam\", \"class\": \"municipality\"}))\r\n    province = forms.CharField(max_length=255, widget=forms.TextInput(attrs={\"placeholder\": \"Noord-Holland\", \"class\": \"province\"}))\r\n    build_year = forms.IntegerField(widget=forms.NumberInput(attrs={\"placeholder\": \"1990\", \"class\": \"build_year\", \"pattern\": \"^[0-9]{4}$\", \"min\": \"1900\", \"max\": \"2022\"}))\r\n    floor_area = forms.DecimalField(widget=forms.NumberInput(attrs={\"placeholder\": \"100\", \"class\": \"floor_area\", \"pattern\": \"^[0-9]{1,3}$\"})) # \"pattern\": \"^[0-9]{1,3}$\"\r\n    geo_x = forms.DecimalField(widget=forms.NumberInput(attrs={\"placeholder\": \"52.123456\", \"class\": \"geo_x\"}))\r\n    geo_y = forms.DecimalField(widget=forms.NumberInput(attrs={\"placeholder\": \"4.123456\", \"class\": \"geo_y\"}))\r\n    rd_x = forms.DecimalField(widget=forms.NumberInput(attrs={\"placeholder\": \"123456\", \"class\": \"rd_x\"})) # Rijksdriehoek\r\n    rd_y = forms.DecimalField(widget=forms.NumberInput(attrs={\"placeholder\": \"123456\", \"class\": \"rd_y\"})) # Rijksdriehoek\r\n```\r\n\r\nThen we can define our template\r\n\r\n```html\r\n{% extends 'base.html' %}\r\n\r\n{% block content %}\r\n   <link rel=\"stylesheet\" href=\"{% static 'postcodes/css/postcodes.css' %}\">\r\n   <script src=\"{% static 'postcodes/js/postcodes.js' %}\" data-api-url=\"{% url \"postcodes:api\" %}\"></script>\r\n\r\n   <form method=\"post\">\r\n       {% csrf_token %}\r\n       {{ form.as_p }}\r\n       <button type=\"submit\">Submit</button>\r\n   </form>\r\n\r\n   ...\r\n\r\n   <script>\r\n       document.addEventListener('DOMContentLoaded', function() {\r\n           lookupPostcode({\r\n               // Add invalid classes to the input fields when they are invalid\r\n               validate: true,\r\n               bind: {\r\n                   // These are required for the lookup\r\n                    postcode: document.querySelector('#id_postcode'),\r\n                    home_number: document.querySelector('#id_home_number'),\r\n\r\n                    // Custom fields returned by the API\r\n                    straat: document.querySelector(\"#id_street\"),\r\n                    woonplaats: document.querySelector(\"#id_city\"),\r\n                    gemeente: document.querySelector(\"#id_municipality\"),\r\n                    provincie: document.querySelector(\"#id_province\"),\r\n                    bouwjaar: document.querySelector(\"#id_build_year\"),\r\n                    vloeroppervlakte: document.querySelector(\"#id_floor_area\"),\r\n\r\n                    // Or optionally as a queryselector\r\n                    // If everything is a string - it is safe to omit the DOMContentLoaded eventListener\r\n                    latitude: \"#id_geo_x\",\r\n                    longitude: \"#id_geo_y\",\r\n                    rd_x: \"#id_rd_x\",\r\n                    rd_y: \"#id_rd_y\",\r\n               },\r\n               success: function(addr) {\r\n                   console.log(addr);\r\n               },\r\n               error: function(error) {\r\n                   console.log(error);\r\n               }\r\n           })\r\n       });\r\n   </script>\r\n\r\n{% endblock %}\r\n```\r\n\r\nThe form will now automatically fill in the address fields when a valid postcode and home number is entered.\r\n\r\nIf it is invalid or not found, the error callback will be called.\r\n\r\n## Settings\r\n\r\n### `ADDR_VALIDATOR_API_KEY`\r\n\r\nThe API key to use for the postcode lookup.\r\n\r\nThis will be used by the `postcodes.postcode.address_check` function.\r\n\r\n\r\n### `ADDR_VALIDATOR_API_URL`\r\n\r\nThe API URL to use for the postcode lookup.\r\n\r\nThis will be used by the `postcodes.postcode.address_check` function.\r\n\r\nIt should contain the `{postcode}` and `{home_number}` placeholders.\r\n\r\n\r\n### `ADDR_VALIDATOR_PARAMETER_FORMAT`\r\n\r\nAn actual function that formats the parameters for the API URL.\r\n\r\nThis may not be a path to a function, but the function itself.\r\n\r\nExample:\r\n\r\n```python\r\ndef default_parameter_formatter(**kwargs):\r\n    return \"&\".join([f\"{key}={value}\" for key, value in kwargs.items()])\r\n```\r\n\r\n\r\n### `ADDR_VALIDATOR_ERROR_ATTRIBUTE`\r\n\r\nThe attribute in the response that contains the error message.\r\n\r\nThis will be used by the `postcodes.postcode.address_check` function.\r\n\r\nAddressValidationError exceptions will return the appropriate error message if the attribute is found.\r\n\r\n\r\n### `ADDR_VALIDATOR_CACHE_TIMEOUT`\r\n\r\nThe timeout for the cache in seconds.\r\n\r\nThis will be used by the `postcodes.postcode.address_check` function.\r\n\r\nIt is highly recommended to set this to a high number; by default it caches for a week.\r\n\r\nThe default endpoint is free to use, but has a rate limit.\r\n\r\n\r\n### `ADDR_VALIDATOR_API_KEY_ATTRIBUTE`\r\n\r\nThe attribute in the response that contains the API key.\r\n\r\nThis will be used by the `postcodes.postcode.address_check` function.\r\n\r\nIt is the header that should be sent with the request.\r\n\r\nDefaults to `X-API-Token`.\r\n\r\n\r\n### `ADDR_VALIDATOR_REQUIRES_AUTH`\r\n\r\nWhether the API requires authentication.\r\n\r\nThis will be used by the internal view to check if the user is authenticated.\r\n\r\nIf the user is authenticated; the view will return the address data.\r\n\r\nThis does not matter if you use the `postcodes.postcode.address_check` function.\r\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-only",
    "summary": "A Django app to manage postcode/home number address forms",
    "version": "1.0.6",
    "project_urls": {
        "Homepage": "https://github.com/Nigel2392/postcodes"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "26a6ea1c4113470c9c8e67b8ff65607c342ebb1bea43ed4d8488c4a029a8edaf",
                "md5": "c435648a25b97530ae84ecad6ce7c138",
                "sha256": "58e13fcd154716af918966099ba25b8a509a54c1c9c2726eedffe101a99e9177"
            },
            "downloads": -1,
            "filename": "django_postcodes-1.0.6.tar.gz",
            "has_sig": false,
            "md5_digest": "c435648a25b97530ae84ecad6ce7c138",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 21825,
            "upload_time": "2024-12-05T10:38:57",
            "upload_time_iso_8601": "2024-12-05T10:38:57.526872Z",
            "url": "https://files.pythonhosted.org/packages/26/a6/ea1c4113470c9c8e67b8ff65607c342ebb1bea43ed4d8488c4a029a8edaf/django_postcodes-1.0.6.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-05 10:38:57",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Nigel2392",
    "github_project": "postcodes",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "django-postcodes"
}
        
Elapsed time: 0.51968s