2

This question is directly related to this question. Can I add the "save_as = True" field on an object with a NestedModelAdmin? If so, is there anything I need to do to get it to properly duplicate/save as new?

I added the field to my admin model which changes my button, but when I click the "save as new" button, it changes the text in that same button to "save and add another". Anything I click after that ("save", "save and continue editing", or "save and add another") returns this error:

Exception Type: ValidationError
Exception Value:    
[u"'' value must be an integer."]

I was able to add the "save_as" field to a different object that had the admin.ModelAdmin and it duplicated an object successfully. I tried implementing the code seen in this question/answer, but I get the same error. I looked through the documentation (at least the little bit I can understand) and I can't find anything that helps. Is this field something that can't added to a NestedModelAdmin? Any pointers of the right direction would be a huge help.

EDIT:

Not sure if this helps, but this a portion of the code from my admin.py file from the elements involved.

class NestedChoiceInline(NestedStackedInline):
    model = Choice
    form = ChoiceInlineForm
    extra = 1
    fk_name = 'question'


class QuestionInline(NestedStackedInline):
    model = Question
    form = QuestionInlineForm
    extra = 1
    fk_name = 'quiz'
    inlines = [NestedChoiceInline]
    exclude = ['order', ]


class QuizAdmin(NestedModelAdmin):
    model = Quiz
    form = QuizForm
    inlines = [QuestionInline]
    list_display = ('name', 'quiz_start_date',
                    'quiz_end_date')
    save_as = True

    # From another answer that I think I need to do to replicate my object 
    # and anything that has a key to it, but I'm not sure
    def save_model(self, request, obj, form, change):
        if '_saveasnew' in request.POST:
            original_pk = resolve(request.path).args[0]
            original_obj = obj._meta.concrete_model.objects.get(id=original_pk)

            for prop, value in vars(original_obj).iteritems():
                if isinstance(getattr(original_obj, prop), FieldFile):
                    setattr(obj,prop,getattr(original_obj, prop))
        obj.save()

I am pretty sure that I understand what that save_model method is doing, but I am not sure which of the parts I may need to customize in order to get everything appropriately assigned/duplicated.

Community
  • 1
  • 1
Alex Lyman
  • 61
  • 1
  • 6
  • I don't fully understand your question, but the error message suggests that you are passing in an object (or an empty string) instead of `object.id` which django is expecting. Can you add a larger code sample to explain the problem? – djq Sep 10 '15 at 17:22
  • Yeah. Let me try and isolate some of my code for you. – Alex Lyman Sep 10 '15 at 18:08

1 Answers1

2

I decided to not use the save_as = True flag, but rather just create my own custom method using deepcopy. I am not sure if copy would've done the exact same as deepcopy, but deepcopy did want I needed.

from copy import deepcopy

def duplicate_quiz(modeladmin, request, queryset):
    for quiz in queryset:
        new_obj = deepcopy(quiz)
        new_obj.id = None
        new_obj.save()

        for question in quiz.questions.all():
            question_copy = deepcopy(question)
            question_copy.id = None
            question_copy.save()
            new_obj.questions.add(question_copy)

            for choice in question.choices.all():
                choice_copy = deepcopy(choice)
                choice_copy.id = None
                choice_copy.save()
                question_copy.choices.add(choice_copy)

        new_obj.save()

duplicate_quiz.short_description = "Duplicate Selected Quizzes"

class QuizAdmin(NestedModelAdmin):
    model = Quiz
    form = QuizForm
    inlines = [QuestionInline, DoubleDownQuestionInline]
    list_display = ('name', 'quiz_start_date',
                    'quiz_end_date')
    actions = [duplicate_quiz]

admin.site.register(Quiz, QuizAdmin)

Not my favorite, but it works.

Alex Lyman
  • 61
  • 1
  • 6