tmoe
tmoe

Reputation: 303

Django - Clone model object in Class based ListView

I have a list.html with lots of records and a column containing a button to clone the specific record like this:

{% for betr in object_list %}
    ....
    <td>
        <button type="button" class="btn btn-first" onclick="window.location='../clone/{{betr.ID}}';">
            <span class="fas fa-copy" style="font-size: 1rem;"></span>
        </button>
    </td>
{% endfor %}

My urls.py looks like this:

urlpatterns = [
...
path('update/<int:pk>/', UpdateView.as_view(), name='update'),
path('clone/<int:pk>/', CloneView.cloneRecord(), name='clone'),
...
]

and my views.py contains a clone view with a function to clone the record and open the UpdateView with the cloned record for editing:

class CloneView(LoginRequiredMixin):
    login_url = '/accounts/login/'
    model = mymodel
    def cloneRecord(self,**kwargs):
        record = mymodel.objects.filter(id=self.request.GET['ID'])[0]
        record.id = None
        record.save()
        return http.HttpResponseRedirect(reverse('/update/', kwargs={'pk':record.id}))

At the moment I am receiving following error:

TypeError: cloneRecord() missing 1 required positional argument: 'self'

What am I missing? Any help is appreciated.

Upvotes: 0

Views: 292

Answers (3)

Mark0
Mark0

Reputation: 21

Here is another variant cloning an object. Biggest advantage is that you open your desired CreateView then it fills in the object from which you have got your id and then you can save it if you want. Don't forget to implement some unique constraint into your model to avoid duplicate records! In this case you won't be in the situation where users are generating useless duplicate records, because it will only be saved when the user really saves it with the submit button in the AssemblyCloneView!

urls.py:

urlpatterns = [
...
path('assembly/clone/<int:pk>/', AssemblyCloneView.as_view(), name='assembly_clone'),

template.html: (using a bootstrap button in my case)

<a class="btn btn-light btn-sm" href="{% url 'engineering:assembly_clone' record.id %}">Clone</a>

views.py:

class AssemblyCloneView(LoginRequiredMixin, CreateView):
    model = Assembly

    """
    Get object desired from url with record.id and override the object context with it.
    """
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        print(context)
        return self.render_to_response(context)

    def get_success_url(self):
        return reverse_lazy('engineering:assembly_detail', kwargs={'pk': self.object.pk})

Upvotes: 1

Muhammad Hassan
Muhammad Hassan

Reputation: 14391

if you have seperate urls for both views, then you should write your code in GET method like this

class CloneView(LoginRequiredMixin, View):
    login_url = '/accounts/login/'

    def get(self,**kwargs):
        record = mymodel.objects.filter(id=self.request.GET['ID'])[0]
        record.id = None
        record.save()
        return http.HttpResponseRedirect(reverse('/update/', kwargs={'pk':record.id}))

Your url should be like this

path('clone/<int:pk>/', CloneView.as_view(), name='clone'),

Remember that as_view is used to call a class based view. You cannot change according to function you are calling.

Upvotes: 0

Saroj Rai
Saroj Rai

Reputation: 1609

remove parenthesis, CloneView.cloneRecord()

path('clone/<int:pk>/', CloneView.cloneRecord, name='clone'),

Upvotes: 0

Related Questions