2

I have two UpdateViews, one works and the other doesn't... Please see Update IV

The working model is:

views.py

class JuryUpdate(UpdateView):
    model = Jury
    fields = [
        'jury_name',
        ]
    template_name_suffix = '_update_form'

    def get_object(self, *args, **kwargs):
        return get_object_or_404(Jury, jury_id=self.kwargs['jr'])

    def form_valid(self, form):
        form.instance.customer_id = self.kwargs['pk']
        form.instance.court_year = self.kwargs['yr']
        form.instance.jury_id = self.kwargs['jr']
        return super(JuryUpdate, self).form_valid(form)

templates/jury_update_form.html (in relevant part)

<div class="container">
    <h5>Update {{for.instance.jury_name}}</h5>
    <form method="post">{% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="Save" />
    </form>
</div>

This setup will render an updateview with the object labels and existing field data from the object. This next setup doesn't work...

views.py

class CustomerUpdate(UpdateView):
    model = Customer
    fields = [
        'customer',
        ]
    template_name_suffix = '_update_form'

    def get_object(self, *args, **kwargs):
        return get_object_or_404(Customer, customer_id=self.kwargs['pk'])

    def form_valid(self, form):
        form.instance.customer_id = self.kwargs['pk']
        return super(CustomerUpdate, self).form_valid(form)

templates/customer_update_form.html (in relevant part)

<div class="container">
    <h5>Update {{form.instance.customer}}</h5>
    <form method="post">{% csrf_token %}
        {{ form.as_p }}
        <input type="submit" value="Save" />
    </form>
</div>

The second updateview does provide an update form but it doesn't populate with the calling object's data. It would seem that the object is there since the {{form.instance.customer}} contains the correct customer data for the call (no different than the JuryUpdate view).

I've tried to explicitly call get_initial (as described here) and print, but the result is {}. I've also tried variation of the form_valid call but as presented above, I believe I'm getting the correct object. There are several examples (such as here) that use get_initial to pre-populate with existing information - but that doesn't work in this instance and it isn't needed in my JuryUpdate view.

Any help is appreciated.

UPDATE I

models.py

class Customer(models.Model):

    class Meta:
        verbose_name = "Customer"
        verbose_name_plural = "Customers"

    customer_id = models.AutoField(
        primary_key=True)

    customer = models.CharField(
        max_length=40)

    # table fields

    def get_absolute_url(self):
        return reverse(
            'customer-detail-view', 
            kwargs={'pk':self.pk})

    def __str__(self):
        return self.customer

class Jury(models.Model):

    class Meta:
        verbose_name = "Jury"
        verbose_name_plural = "Juries"

    customer = models.ForeignKey(
        Customer,
        on_delete=models.CASCADE)

    court_year = models.ForeignKey(
        CourtYear,
        on_delete=models.CASCADE)

    jury_id = models.AutoField(
        primary_key=True)

    jury_name  = models.CharField(
        max_length=20)

    # other table fields

    def get_absolute_url(self):
        return reverse(
            'jury-list-view', 
            kwargs={'pk':self.customer_id, 'yr':self.court_year_id})

    def __str__(self):
        return self.jury_name

urls.py

path('add_customer/', views.CustomerCreate.as_view(), name='customer-add'),
path('<int:pk>/', views.CustomerDetailView.as_view(), name='customer-detail-view'),
path('<int:pk>/delete/', views.CustomerDelete.as_view(), name='customer-delete'),   
path('<int:pk>/update/', views.CustomerUpdate.as_view(), name='customer-update'),

path('<int:pk>/<int:yr>/', views.JuryListView.as_view(), name='jury-list-view'),
path('<int:pk>/<int:yr>/add_jury/', views.JuryCreate.as_view(), name='jury-add'),
path('<int:pk>/<int:yr>/<int:jr>/updatejury', views.JuryUpdate.as_view(), name='jury-update'),
path('<int:pk>/<int:yr>/<int:jr>/deletejury', views.JuryDelete.as_view(), name='jury-delete'),

UPDATE II

I've added a get_initial() method to my CustomerUpdate(UpdateView) as follows:

def get_initial(self):

    initial = super(CustomerUpdate, self).get_initial()
    print('initial data', initial)

    customer_object = self.get_object()

    initial['customer'] = customer_object.customer
    # other fields omitted...

    print('initial data updated', initial)

    return initial

The initial data print returns {}. The initial data updated print returns {'customer': 'John Doe'} (plus the "other fields"). So it seems that the right information is getting pulled and delivered - It must be in the html?

Update III

I've taken the CustomerUpdate(UpdateView) down to the very basic class model:

class CustomerUpdate(UpdateView):
    model = Customer
    fields = [
        'customer',
        ]
    template_name_suffix = '_update_form'

The template is already the basic format (docs) - the rendered webpage still doesn't have object data for updating...

Update IV

I think I've figured out the problem - but don't know how to fix...

When I use the JuryUpdate call the console shows:

[02/Jun/2018 16:19:19] "GET /myapp/1/3/9/updatejury/?csrfmiddlewaretoken=1kHK4xgqdbBfXsv6mtz0WKgKpewFwLVtpUX5Z51qnLsGaMDVmpdVHKslXAXPhvY8 HTTP/1.1" 200 3687

When I use the CustomerUpdate call the console shows:

[02/Jun/2018 16:18:57] "POST /myapp/5/update/ HTTP/1.1" 200 3354

So my updateview on the Jury update is a GET call while my udpateview on Customer is aPOST call. In looking through the docs, I can see that the GET call with show the data while the POST call is (I think) assuming a black data set. I can't figure out why I'm getting a different result - where would this be set/changed?

Bill Armstrong
  • 1,615
  • 3
  • 23
  • 47
  • Before looking further — the "Customer" field in `CustomerUpdate` should probably be lower-case? Impossible to be certain without looking at your models, but your narrative suggests that's the wrong capitalisation. (This may or may not be the cause of your actual problem, though.) – James Aylett Jun 01 '18 at 19:07
  • @JamesAylett - my typo on SO - fixed. – Bill Armstrong Jun 01 '18 at 19:09
  • Does your `Customer` really have a `customer` field? That seems…unexpected. It highlights that this isn't a complete enough view to see what's going on — your urlconf and models may be needed for someone to help. – James Aylett Jun 01 '18 at 19:18
  • Use Python 3 so you don't need to rewrite this in a year and a half when Python 2 looses all support. – kagronick Jun 02 '18 at 00:47
  • @kagronick - this is running in 3.6.5 (?) – Bill Armstrong Jun 02 '18 at 04:03
  • 1
    @Bill super() doesn't need arguments on Python 3. Most people don't put it because it breaks the DRY rule and makes it harder to refactor class names. – kagronick Jun 03 '18 at 13:35

1 Answers1

0

After 3 days - I traced the issue - it had nothing to do with the view, model, url or the update template. The offending code was actually attached to the update button. Very specifically the page that had the button for "Update" used the following <form> code:

<form action="{% url 'customer-update' pk=customer.client_id %}" method="post" style="display: inline;">
    {% csrf_token %}
    <button type="submit" class="btn btn-outline-primary btn-custom-xs">U</button>
</form>

In the form call the method used was "POST" - and although I don't exactly understand the intracacies, the result is a blank UpdateView. The following code in the calling page fixed the problem.

<form action="{% url 'customer-update' pk=customer.client_id %}" style="display: inline;">
    {% csrf_token %}
    <button type="submit" class="btn btn-outline-primary btn-custom-xs">U</button>
</form>
Bill Armstrong
  • 1,615
  • 3
  • 23
  • 47