django-address
django-address copied to clipboard
Getting dictionary values from built in form
Does the built in form allow me to save the addressed parsed into the different dictionary values?
When I use the form, I can only see one input "address" and when saving model instance, it just populates the "raw" field.
models.py
class UserAddress(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name="user_address")
address = AddressField()
views.py
@login_required
def addaddress(request):
address = request.POST['address']
addr = UserAddress(user=request.user, address=address)
addr.save()
print(addr)
As seen in Django-Admin
@jeffykle , it does perform the parsing but only in conjunction with the jquery script that queries googles places api. The autocomplete suggestions will be automatically broken into the components you seek. See the example for a demo.
If you cannot use the places api, I recommend creating a form that collects the components. After validating them, you can Address.objects.create(..)
a new address specifying the components from the form field. See Setting Values in the readme.
Please let me know if this isn't clear or if you have a suggestion for changes to how it behaves or the documentation.
@banagale Thanks for your input. It wasn't clear to me how it worked as I was using the form provided with the template tag in the readme which only had one visible input field. Now after more inspection I see I can directly access the address components within the form after selecting a result.
On a separate note, it might be nice to leave some hints on how to customize the form. I found it easiest to use django-widget-tweaks so I could quickly add a Bootstrap class to the input field and change or remove the input label.
https://github.com/jazzband/django-widget-tweaks
{% for field in address_form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field|add_class:"form-control w-100" }}
</div>
{% endfor %}
@jeffykle You'e welcome. Would you please describe a bit more what your goal was from the start and perhaps a screenshot of the UI you ended up with?
If I can, I want to make sure we at least address the use case with ideally a few directions on how to implement it in the docs. (Including, perhaps the widget tweaks method you described)
Re-opening with the hope of capturing this and converting into a documentation issue.
Sure, my use case is to capture shipping addresses and save them to a user's profile (specifically U.S. only in my case).
I'll get the address components with jquery and pass them to a django view with an ajax call. It will add a new address if the user doesn't already have that one saved, and select it in the billing form.
addAddressForm.on('submit', function(e) {
e.preventDefault()
const form = new FormData(e.target);
const address = {}
const csrf_token = form.get("csrfmiddlewaretoken");
const select = document.querySelector('#address-select')
$('#address_components').children().each(function(i, e) {
address[e.dataset.geo] = e.value
})
const url = "/shop/addaddress/"
$.ajax({
url: url,
type: 'POST',
headers: { "X-CSRFToken": csrf_token },
data: {
'address': JSON.stringify(address),
},
dataType: 'json',
success: function (data) {
$('#address-select').empty();
for (const obj in data.addresses) {
console.log(obj)
var option = $('<option></option>').attr("value", data.addresses[obj]['id']).text(data.addresses[obj]['address']);
if (data.addresses[obj]['selected']) { option.prop('selected', true)}
$('#address-select').append(option);
$('#id_address').val('');
}
}
})
})
I believe the dataset.geo attributes of the form come from this package, and if so, it would be nice to update them so they match the dictionary values used for saving the address object in Django. As you can see I had to remap some of the field names, but it would be much simpler without doing so.
views.py
@login_required
def addaddress(request):
all_addresses = []
result = json.loads(request.POST['address'])
remapCols = {
'raw': 'formatted_address' ,'street_number': 'street_number' ,'route': 'route' ,'locality': 'locality' ,
'postal_code': 'postal_code' ,'state': 'administrative_area_level_1' ,'state_code': 'administrative_area_level_1_short' ,
'country': 'country' ,'country_code': 'country_short','latitude': 'lat','longitude': 'lng'}
address = {}
for key, value in remapCols.items():
address[key] = result[value]
is_new = True
for a in UserAddress.objects.filter(user=request.user):
if str(a.address) == address['raw']:
all_addresses.append({'address': a.address.raw,'id':a.id, 'selected': True})
is_new = False
else:
all_addresses.append({'address': a.address.raw,'id':a.id, 'selected': False})
if is_new:
addr = UserAddress(user=request.user, address=address)
addr.save()
all_addresses.append({'address': addr.address.raw,'id':addr.id, 'selected': True})
data = {'addresses': all_addresses}
return JsonResponse(data)
Finally, I have to figure out how to add a "Street Address #2" field, possibly appending it to one of the existing fields, or just adding an extra field to my UserAddress
model above, so that users can specify things like Apartment number, unit number, or other text such as ATTN: Manager, etc.
@jeffykle Thank you for this additional set of information on your use case. I will carefully at your implementation and suggestions. I'm leaving this ticket open for now, so I can be sure it gets looked at.