2

I have created a Form, where the User sets an Alarm object. The Alarm object saves as expected to the database. However, the issue is that: another object, which contains only the information completed in the Form, also saves to the database.

As I understand, form_valid() for CreateView saves the form. I have tried the two solutions suggested in another query with no success. I suspect that the issue is caused by either return super().form_valid(form) or by Alarm.objects.create() in create_alarm_object().

Views.py

class AlarmCreateView(LoginRequiredMixin, CreateView):
    """ CreateView for User to create the Alarm object """
    model = Alarm
    form_class = SetAlarmForm
    template_name = 'weather_alarm/set_alarm.html'
    login_url = "/login/"

    def form_valid(self, form):
        self.create_alarm_object(request, form)
        return super().form_valid(form)

    def get_success_url(self, **kwargs):
        return reverse("weather_alarm:active-alarm", kwargs={'pk':self.object.pk})

    def create_alarm_object(self, request, form):
        """ Function to get User's location from IP and create Alarm object """
        ...
        alarm_object = Alarm.objects.create(
            alarm_id=uuid.uuid4(),
            user=self.request.user,
            timezone=user_timezone,
            city=location.raw['address']['city'],
            country=location.raw['address']['country'],
            time=form.cleaned_data['time'].astimezone(pytz.timezone(user_timezone)),
            temp_conditional=form.cleaned_data['temp_conditional'],
            surf_conditional=form.cleaned_data['surf_conditional'],
            temp_max=form.cleaned_data['temp_max'],
            temp_min=form.cleaned_data['temp_min'],
            surf_max=form.cleaned_data['surf_max'],
            surf_min=form.cleaned_data['surf_min'],
        )
        alarm_object.save()
Darcy
  • 575
  • 2
  • 8
  • 21

1 Answers1

1

You've debugged it right. super call to form_valid and method create_alarm_object are creating two objects.

As you can see in form_valid method implementation, it saves the form and returns a HttpResponseRedirect object using success_url.

Either, do not override form_valid method or, use the following code.

Solution:

def form_valid(self, form):
    self.create_alarm_object(self.request, form)
    return HttpResponseRedirect(self.get_success_url())

EDIT:

Update create_alarm_object method to set self.object and remove redundant save call.

def create_alarm_object(self, request, form):
    self.object = Alarm.objects.create(...)
    # no `save` call needed, `create` already creates and returns the saved object.
Sachin
  • 3,576
  • 1
  • 15
  • 24
  • I tried the later solution suggested and received the following error: `AttributeError: 'NoneType' object has no attribute 'pk'`. Note, `Primary_Key=True` for `alarm_id`. Do I need to refer to `alarm_id` in `get_success_url()`? However, I checked the database and the Alarm object is now correctly saving one object! – Darcy Aug 10 '18 at 23:48
  • Apologies. `return reverse("weather_alarm:active-alarm", kwargs={'pk':self.object.pk})` – Darcy Aug 10 '18 at 23:50
  • 1
    That is a different problem. Though you can solve it easily by setting `self.object` in `create_alarm_object` method to the one you created. – Sachin Aug 10 '18 at 23:52