Skip to content

Commit

Permalink
Merge pull request #1 from plathanus-tech/feature/widget
Browse files Browse the repository at this point in the history
Feature/widget
  • Loading branch information
leandrodesouzadev authored Mar 2, 2022
2 parents 6d52c05 + 97a3fb6 commit d710873
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 10 deletions.
97 changes: 87 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,36 @@ class YourForm(forms.Form):

```python
# your_app/views.py
from django.http import HttpRequest
from django.http import HttpRequest, HttpResponse
from brazilian_zipcode import BrazilianAddress
from your_app.forms import YourForm


def your_view(request: HttpRequest):
form = YourForm(data=request.POST)
form.is_valid(raise_exception=True)

form.zipcode_info # This attr is an instance of: `BrazilianAddress`
print(form.zipcode_info.street)
print(form.zipcode_info.zipcode)
print(form.zipcode_info.district)
print(form.zipcode_info.city)
print(form.zipcode_info.state_initials)
if not form.is_valid():
return HttpResponse(status=400)

zipcode_info = form.cleaned_date.get("zipcode_info")
print(zipcode_info.street)
print(zipcode_info.zipcode)
print(zipcode_info.district)
print(zipcode_info.city)
print(zipcode_info.state_initials)

return HttpResponse(status=200)
```

```python
# your_app/urls.py

from django.urls import path
from . import views

urlpatterns = [
...
path('your_view/', views.your_view)
]
```

### As an API
Expand Down Expand Up @@ -75,9 +88,70 @@ That returns a `JSON` like:

If the service is unavailable, you may receive a 404 response.


### As an Widget (Requires the API step)

You can use this widget to automatically show the address on the admin using the widget `AutoBrazilianZipCodeInput`.
After the user inputs the zipcode, it will make an get request to the API endpoint and displays the result directly on the admin.
Follow these steps:

1; Create your form:

```python
# your_app.forms.py

from django import forms
from brazilian_zipcode import BrazilianZipCodeField
from brazilian_zipcode.widgets import AutoBrazilianZipCodeInput
from your_app.models import YourModel


class MyAddressForm(forms.ModelForm):
# Here we used ModelForm, but you can use any other form.

zipcode_info = BrazilianZipCodeField(widget=AutoBrazilianZipCodeInput())

class Meta:
model = YourModel
fields = ['zipcode_info']

```

2; Set the widget on the field:

```python
# your_app.forms.py

class MyAddressForm(forms.ModelForm):
# Here we used ModelForm, but you can use any other form.

zipcode_info = BrazilianZipCodeField(widget=AutoBrazilianZipCodeInput())
# You can also use any other CharField you like
```

3; Set the form on the admin:

```python
# your_app.admin.py

from django.contrib import admin
from .models import Address
from .forms import MyAddressForm

# Register your models here.
@admin.register(Address)
class MyAdressAdmin(admin.ModelAdmin):
form = MyAddressForm

```

4; Collect the required JavaScript:
> python3 manage.py collectstatic
### Writing your own Address Retrieve Service

To provide your own service for retrieving addresses, you should:
You can also provide your custom service for retrieving addresses. This will be used on all use cases stated above.
To do so you should:

1; Create a Class that implements an `classmethod` called `get_address_info`:

Expand Down Expand Up @@ -124,3 +198,6 @@ class YourAddressRetrievingService:
ADDRESS_PARSER_CLASS = "your_app.module.YourAddressRetrievingService"

```


Enjoy! :D
1 change: 1 addition & 0 deletions src/brazilian_zipcode/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .forms import BrazilianZipCodeField
from .widgets import AutoBrazilianZipCodeInput
from .objects import BrazilianAddress
88 changes: 88 additions & 0 deletions src/brazilian_zipcode/static/getAddressInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const zipcodeSelector = "[meta_id='meta_zipcode_info']";
const saveButtonSelector = "[name='_save']"

function isNumeric(str) {
if (typeof str != "string") return false
return !isNaN(str) &&
!isNaN(parseFloat(str))
}

function onlyDigits(value) {
return value.replace(/\D/g, "")
};

function removeReadOnlyInput(label) {
const previousElement = document.querySelector(`[meta-id='${label}']`);
if (previousElement !== null) {
previousElement.remove();
}
}

function createReadOnlyInput(label, value) {
const input = document.querySelector(zipcodeSelector);
const parentDiv = input.parentNode.parentNode.parentNode;

removeReadOnlyInput(label);
const div = document.createElement("div");
div.classList.add("form-row");
div.setAttribute("meta-id", label)

const valueDiv = document.createElement("div");
const labelElement = document.createElement("label");

labelElement.innerText = label + ":";
labelElement.classList.add("required");
div.appendChild(labelElement);

valueDiv.classList.add("readonly");
valueDiv.innerText = value;
div.appendChild(valueDiv);

parentDiv.appendChild(div);
}

function getAddressInfo(zipcode) {
const saveButton = document.querySelector(saveButtonSelector);

fetch(`/api/address_info?zipcode=${zipcode}`).then((response) => {
if (response.status !== 200) {
saveButton.setAttribute('disabled', true)
removeReadOnlyInput("Rua");
removeReadOnlyInput("Bairro");
removeReadOnlyInput("Cidade");
removeReadOnlyInput("UF");
window.alert("CEP não encontrado ou serviço indisponível");
return
}
response.json().then(data => {
createReadOnlyInput("Rua", data.street);
createReadOnlyInput("Bairro", data.district);
createReadOnlyInput("Cidade", data.city);
createReadOnlyInput("UF", data.state_initials);
})
})
saveButton.removeAttribute('disabled');
};

function handleOnFocusOutEvent(event) {
var zipcode = event.target.value;
zipcode = onlyDigits(zipcode);

const input = document.querySelector(zipcodeSelector);
input.value = zipcode;

if (zipcode.length !== 8) {
return;
}
if (!isNumeric(zipcode)) {
return
}
getAddressInfo(zipcode);
};



$(document).ready(function () {
const input = document.querySelector(zipcodeMetaId);
input.addEventListener("focusout", handleOnFocusOutEvent)
});
11 changes: 11 additions & 0 deletions src/brazilian_zipcode/widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.forms import widgets
from django.utils.safestring import mark_safe


class AutoBrazilianZipCodeInput(widgets.TextInput):
def render(self, name, value, **attrs):
attrs["meta_id"] = "meta_zipcode_info"
return super().render(name, value, attrs)

class Media:
js = ("getAddressInfo.js",)

0 comments on commit d710873

Please sign in to comment.