Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting dictionary values from built in form #133

Open
jeffykle opened this issue Sep 20, 2020 · 5 comments
Open

Getting dictionary values from built in form #133

jeffykle opened this issue Sep 20, 2020 · 5 comments
Assignees

Comments

@jeffykle
Copy link

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
image

@banagale
Copy link
Collaborator

@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.

@jeffykle
Copy link
Author

@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.

image

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 %}

@banagale
Copy link
Collaborator

@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.

@banagale banagale reopened this Sep 21, 2020
@jeffykle
Copy link
Author

Sure, my use case is to capture shipping addresses and save them to a user's profile (specifically U.S. only in my case).

image

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.

@banagale
Copy link
Collaborator

@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.

@banagale banagale self-assigned this Oct 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants