0

Imagine this concept, I have a Taxi that can be ordered by a group for a full day multiple visits, and I should assign a group leader for each booking. now I have a Booking (PNR) that holds Clients traveling Routes, and a Group Leader (Operator) assigned for that booking.

my view holds these:

  1. form for selecting the operator
  2. formset to add clients

in this view I'm trying to make it easier for the user by giving the ability to save each form separately by ajax or save all data of forms by a button at the bottom of the view.

I've been searching for a few days and I got the nearest approach on these two linkes 1 & 2 but still can't make my code run correctly and do what it's supposed to do. :( ANY SUPPORT WILL BE HIGHLY APPRECIATED!

My models.py:

class Operator (models.Model):
    name = models.CharField(max_length=50)
    # Other Fields

    def __str__(self):
        return self.code


class PNR (models.Model):
    date_created = models.DateTimeField(auto_now_add=True)
    # Other Fields

    def __str__(self):
        return self.pk


class Client (models.Model):
    related_pnr = models.ForeignKey(PNR, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    # Other Fields

    def __str__(self):
        return self.related_pnr+" "+self.name

My forms.py:

class ChooseOperatorCode(forms.Form):
    operator = forms.ModelChoiceField(queryset=Operator.objects.all())

    def clean(self, *args, **kwargs):
        operator = self.cleaned_data.get('operator')

        return super(ChooseOperatorCode, self).clean(*args, **kwargs)


class NewClientForm(forms.Form):
    name = forms.CharField(widget=forms.TextInput(attrs={}), label=False, max_length=200)
    # Other Fields

    def clean(self, *args, **kwargs):
        name = self.cleaned_data.get('name')
        # Other Fields

        return super(NewClientForm, self).clean(*args, **kwargs)

My views.py:

@login_required
def create_pnr(request):

    pnr = PNR.objects.create(created_by_user=request.user)

    choose_operator_form = ChooseOperatorCode(request.POST or None)
    if choose_operator_form.is_valid():
        pnr.created_by_operator = choose_operator_form.cleaned_data.get('operator')
        pnr.save()
        choose_operator_form.save()

    clients_form = NewClientForm(request.POST or None)
    if clients_form.is_valid():
        client = Client()
        client.related_pnr = pnr.pk
        client.name = clients_form.cleaned_data.get('name')
        client.save()
        clients_form.save()
    context = {
        'pnr': pnr.pk,
        'choose_operator_form': choose_operator_form,
        'clients_form': clients_form,
    }
    return render(request, 'reservation_new.html', context)


@login_required
def edit_pnr(request, pnr_id):
    pnr = PNR.objects.get(id=pnr_id) 

    choose_operator_form = ChooseOperatorCode(request.POST or None)
    if choose_operator_form.is_valid():
        pnr.created_by_operator = choose_operator_form.cleaned_data.get('operator')
        pnr.save()

    clients_form = NewClientForm(request.POST or None)
    if clients_form.is_valid():
        client = Client()
        client.related_pnr = pnr.pk
        client.name = clients_form.cleaned_data.get('name')
        client.save()
        clients_form.save()
    context = {
        'pnr': pnr.pk,
        'choose_operator_form': choose_operator_form,
        'clients_form': clients_form,
    }
    return render(request, 'reservation_edit.html', context)

My url.py:

    path('operation/reservation/new/', views.create_pnr, name='new_pnr'),
    path('operation/reservation/existing/<int:pnr_id>/', views.edit_pnr, 
       name='existing_pnr'),

And Finally my template.html: (for both new and edit)

<form  method="POST" action="{% url 'existing_pnr' pnr_id=pnr %}" id="choose_operator_form">
     {% csrf_token %}
     {{choose_operator_form}}
</form>
<form  method="POST" action="{% url 'existing_pnr' pnr_id=pnr %}" id="clients_form">
     {% csrf_token %}
     {{clients_form}}
</form>
<script type="javascript">
    $(document).('submit', '#choose_operator_form', function(e){
        e.preventDefault();

        $.ajax({
            type:'POST',
            url:"{% url 'existing_pnr' %}",
            data: $('#choose_operator_form').serialize(),
            success: function (result) {
                // show success msg
            },
            error: function (data) {
                // show error msg
            }
        });
    });

    //same code for clients form
</script>
15
  • What's the problem? What isn't working? Are you getting errors? Is some part of your code not doing what you expect it to do? Commented Apr 6, 2020 at 16:46
  • two things I wanna know, can I actually apply this concept give user ability to save each form separately with ajax and ability to submit all forms and formsets at once? and how to apply this approach? the second thing that it giving me errors that when I hit save for choose_Operator_form says 'WSGIRequest' object has no attribute 'pnr' Commented Apr 6, 2020 at 16:56
  • yes, conceptually you can do that, as long as you remove the form after it was successfully submitted via ajax, so that it doesn't get submitted twice if the user then clicks "submit all". Commented Apr 6, 2020 at 16:59
  • 1
    But I told you, why would you expect request.pnr to work? Where is pnr coming from? Django has no idea of pnr. Normally, in an edit view, you have the id of the object to edit in the url, define a variable in the path (urls.py) and pass it to your view that would be def edit_pnr(request, pnr_id): .... Commented Apr 6, 2020 at 17:08
  • 1
    {% url 'existing_pnr' pnr_id=pnr %} and path('../<int:pnr_id>/', ...) Commented Apr 7, 2020 at 10:01

1 Answer 1

1

The pnr doesn't get added to the request object, so request.pnr makes no sense. You need to pass the id of the PNR through the URL, that way it can be accessed in the view:

  • In urls.py, make sure that the url for your edit_pnr view gets the pnr_id: something like path('pnr/<int:pnr_id>/edit/', ..., name="existing_pnr").
  • In your template, construct the url for editing a pnr like this: {% url 'existing_pnr' pnr_id=pnr %}
  • In your view, receive the pnr_id: def edit_pnr(request, pnr_id): ...

Now you can fetch the PNR that's being edit like this: pnr = get_object_or_404(PNR, pk=pnr_id) which will correctly return a 404 Not Found if someone tries to access a non-existing PNR.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.