0

I have followed the guidelines from This answer in order to pass Parent pk to the child creation page. At the moment though it is not working and I am seeing the following log.

[14/Jul/2017 13:15:37] "POST /catalog/productstatus/2/create/ HTTP/1.1" 200 4001

I'm not sure what I'm doing wrong, here is the code I currently have.

Models

Models.py

class Product(models.Model):
    serial_number = models.CharField(unique=True, max_length=15)

class ProductStatus(models.Model):
    serial_number = models.ForeignKey('Product', on_delete=models.CASCADE, null=True)
    status = models.CharField(max_length=20,  blank=True, default='Stock', help_text='Products status')
    date = models.DateTimeField(auto_now_add=True)

View

class ProductStatusCreate(CreateView):
    model = ProductStatus
    template_name = 'catalog/productstatus_create.html'
    form_class = ProductStatusModelForm

    def form_valid(self, form):
        productstatus = form.save(commit=False)
        product_id = form.data['product_id']
        product = get_object_or_404(Product, id=product_id)
        productstatus.product = product 
        return super(ProductStatusCreate, self).form_valid(form)

    def get_context_data(self, **kwargs):
        context = super(ProductStatusCreate, self).get_context_data(**kwargs)
        context['s_id'] = self.kwargs['product_id']
        return context

    def get_success_url(self):
        if 'product_id' in self.kwargs:
            product = self.kwargs['product_id']
        else:
            product = self.object.product.pk
        return reverse_lazy('product_detail', kwargs={'pk': product})

Forms

class ProductStatusModelForm(forms.ModelForm):

    class Meta:
        model = ProductStatus
        fields = ['status',]

    def __init__(self, *args, **kwargs):
        self.fields["product"] = forms.CharField(widget=forms.HiddenInput())
        super(ProductStatusModelForm, self).__init__( *args, **kwargs)

templates/myapp/product_detail.html

<a href="{% url 'productstatus_create' product_id=product.id %}">New</a>

urls.py

urlpatterns += [  
url(r'^productstatus/(?P<product_id>\d+)/create/$', views.ProductStatusCreate.as_view(), name='productstatus_create'),
]

productstatus_create.html

{% extends "base_generic.html" %}
{% block content %}


<h2>New Product Status</h2>
</br>
<form action="" method="post">

  {% csrf_token %}
  <table>
  <input type=hidden id="id_product" name="product" value="{{ s_id }}">
  {{ form }}
  </table>
  <input type="submit" value="Submit" />
</form>
</br>

{% endblock %} 

When looking at the page's source the value does get populated but when I submit the form nothing happens.

RBDB_01
  • 15
  • 4

2 Answers2

0

Why do you have views.ProductInstanceCreate.as_view() in your urls.py but the view you show is called ProductStatusCreate? Are you sure you are using the right view?

  • Sorry, those were typos from when I was transcribing the question I have now updated it and so it should all now be correct. – RBDB_01 Jul 15 '17 at 15:03
0

You are creating a 'product' hidden field in your form, but not providing a value for it anywhere. Your template output then has two product fields, and the latter (blank) is taken, so returns an error saying it is required.

None of this outputting the product ID to the template in order to read it back in is necessary - you always have the ID available to you in the URL kwargs.

You can get rid of your get_context_data, and the extra field code in the Form and template. Your form_valid can be something like:

def form_valid(self, form):
    product = get_object_or_404(Product, id=self.kwargs['product_id'])
    form.instance.product = product
    return super().form_valid(form)

And product_id will always be in self.kwargs, so your get_success_url can be shorter too:

def get_success_url(self):
    product = self.kwargs['product_id']
    return reverse('product_detail', kwargs={'pk': product})
M Somerville
  • 4,499
  • 30
  • 38