Reputation: 559
So... I try to explain : I have a "generic" model (who should certainly be abstract) GenericProduct and his child model Product. This gives me 2 tables with some entries of course. I want to be able to duplicate an entry, via templates. To do that (Class-based view), I created a class Duplicate(CreateView, UpdateView) adn I've overwritten the method get_object to set the "pk" to "None". It works, but the pk I get is the pk of the second table... So the "duplication" doesn't work... I can give you some code to test.
But am I doing it the right way ? In my Generic model I've also created a method
def duplicate(self):
self.save(force_insert=True)
How could I use it ?
Thanks
Edit : adding code
models.py
from django.db import models
class GenericProduct(models.Model):
name = models.CharField(max_length=100, unique=True)
name = models.CharField(max_length=100)
def duplicate(self): # can it help ?
self.save(force_insert=True)
class Product(GenericProduct):
pass
form.py
from django.forms.models import ModelForm
class ProductForm(ModelForm):
class Meta:
model = Product
fields = '__all__'
views.py (~CRUD)
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView
from django.core.urlresolvers import reverse_lazy
class List(ListView):
model = Product
context_object_name = "products"
template_name = "products.html"
class Update(UpdateView):
model = Product
form_class = ProductForm
template_name = "product.html"
success_url = reverse_lazy('products')
def get_object(self):
reference = self.kwargs['reference']
p = self.model.objects.get(reference=reference)
p.pk = None
return p
class Duplicate(CreateView, UpdateView):
model = Product
template_name = "product.html"
success_url = reverse_lazy('products')
form_class = ProductForm
def get_object(self):
reference = self.kwargs['reference']
p = self.model.objects.get(reference=reference)
p.genericproduct_ptr_id = None
return p
products.html (to get the list)
<html>
<body>
<style>
table {
border: 1px solid black;
border-collapse: collapse;
}
td, th {
border: 1px solid black;
padding: 3px 7px;
}
</style>
<table>
<tr>
<th>actions</th>
<th>reference</th>
<th>name</th>
</tr>
{% for product in products %}
<tr>
<td>
<a href="{% url 'duplicate' product.reference %}">duplicate</a>
</td>
<td>
<a href="{% url 'update' product.reference %}">
{{ product.reference }}
</a>
</td>
<td>{{ product.name }}</td>
</tr>
{% empty %}
<tr>
<td>no entry</td>
</tr>
{% endfor %}
</table>
</body>
</html>
product.html (to edit/duplicate a product)
<html>
<body>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="OK" />
</form>
<p>
<a href="{% url 'products' %}">
back to list of products
</a>
</p>
</body>
</html>
Upvotes: 1
Views: 970
Reputation: 559
I make my comment as answer as I am satisfied of it :-) !!
So in models.py, no need of def duplicate(self): self.save(force_insert=True)
In views.py, no need of the Duplicate
class.
I add too the urls.py :
from django.conf.urls import url
urlpatterns = [
url(r'^products/?$', List.as_view(), name='products'),
url(r'^create/?$', Create.as_view(), name='create'),
url(r'^edit/(?P<reference>.*)/?$', Update.as_view(), name='update'),
url(r'^duplicate/(?P<reference>.*)/?$', Update.as_view(), name='duplicate'),
]
And where it become possible, in product.html :
<html>
<body>
{% if "duplicate" in request.path|cut:"/" %}{% url "create" as URL %}{% endif %}
<form action='{{ URL }}' method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="OK" />
</form>
<p>
<a href="{% url 'products' %}">
back to list of products
</a>
</p>
</body>
</html>
The trick is to parse the URL to know if we display the form as a creation or as a duplication. We also could pass an argument in the url configuration, but we already have the information in the URL, so... And then, the form is sent to the action attribute value : "" (empty) if update, creation URL if duplication. That's all.
Regards,
Upvotes: 1