form_invalid метод не отображает ошибочные поля - PullRequest
0 голосов
/ 20 июня 2020

У меня есть CBV CreateView и форма django, которая ведет себя правильно, когда вы вводите правильные данные. Однако, если в форме есть поля с ошибкой (повторяющийся номер телефона или несколько основных контактных телефонов), то она повторно отображается с помощью метода form_invalid, но поля, которые были ранее заполнены, теперь отображаются пустыми.

Поле customUser в модели телефона, которое является внешним ключом для модели пользователя CustomUser (AbstractUser), кажется пустым, когда я печатаю данные request.post.

Это моя модель:

class Phone(models.Model):

   COUNTRIES = (
       (55, _('Brazil')),
       (1, _('United States of America')),
   )
   PHONETYPES = (
       ('1', _('Mobile')),
       ('2', _('Home')),
       ('3', _('Work')),
       ('4', _('Other')),
   )
   status = models.CharField(_("Record Status"), max_length=1, default='A')
   status_dt = models.DateTimeField(_("Status Date"), default=timezone.now)
   customUser = models.ForeignKey(CustomUser, verbose_name=_("User"), on_delete=models.CASCADE)

   phone_name = models.CharField(_("Phone name"), max_length=20, default="PH"+str(random.randint(1,99999)))

   country = models.IntegerField(_("Country Dialing Code"), choices=COUNTRIES)
   
   phone_number = models.CharField(_("Phone Number"), max_length=11)

   phone_type = models.CharField(_("Phone Type"), max_length=1, default="4", choices=PHONETYPES)

   verified = models.BooleanField(verbose_name=_('verified'), default=False)
   primary = models.BooleanField(verbose_name=_('primary'), default=False)

   at_user = models.CharField(_("Audit Trail (user)"), max_length=255, blank=True)
   at_ip = models.GenericIPAddressField(_("Audit Trail (IP)"), protocol='both', blank=True, null=True)
   at_dttm = models.DateTimeField(_("Audit Trail (Date-Time)"), default=timezone.now)
   at_action = models.CharField(_("Audit Trail (Function performed)"), max_length=255, blank=True)
   UniqueConstraint(fields=['customUser', 'country', 'phone_number'], name='user_unique_phone_number')

   class Meta:
        verbose_name = _("Phone Number")
        verbose_name_plural = _("Phone Numbers")
           
   @classmethod
   def create(cls, user):
       phone = cls(customUser = CustomUser.objects.get(id=user))
       # phone create
       return phone

   def __str__(self):
        return self.phone_name


Это моя форма:

class PhoneForm(forms.ModelForm):
    
  class Meta:
    model = Phone
    
    fields = 'customUser', 'phone_name', 'country', 'phone_number', 'phone_type', 'primary'
    widgets = {'customUser': forms.HiddenInput()} 

  def __init__(self, *args, **kwargs):
        
        self.request = kwargs.pop('request', None)
       
        super(PhoneForm, self).__init__(*args, **kwargs)
        self.fields['customUser'].widget.attrs['readonly'] = True
        self.fields['primary'].help_text = _('<strong>Check:</strong> If this is your main contact phone number.')
   

  def clean(self):
        
        cleaned_data = super(PhoneForm, self).clean()
        
        customUser = CustomUser.objects.get(id=self.request.user.id)
        phone_name = cleaned_data.get('phone_name')
        country = cleaned_data.get('country')
        phone_number = cleaned_data.get('phone_number')
        phone_type = cleaned_data.get('phone_type')
        primary = cleaned_data.get('primary')
                       
        if "action_add" in self.request.POST:
            
            try:
                phonenum = Phone.objects.filter(customUser=customUser, country=country, phone_number=phone_number).first()
                if phonenum:
                    #messages.error(self.request, _('This Phone is registered already.')) 
                    raise forms.ValidationError(_('This Phone is registered already.'), code='invalid')
            except Phone.DoesNotExist:
                pass
            
            try:
                phone = Phone.objects.filter(customUser=customUser, primary=True).first()
                if phone and primary:
                    
                    #messages.error(self.request, _('There is another "Primary" Phone already.'))
                    raise forms.ValidationError(_('There is another "Primary" Phone already.'), code='invalid')
                    
            except Phone.DoesNotExist:
                pass
            
        if "action_update" in self.request.POST:
          
          if "country" in self.changed_data or "phone_number" in self.changed_data:
                        
            raise forms.ValidationError(_('You can´t update the Country nor the Phone number of the existing Phone.'), code='invalid')
          try:
              phone = Phone.objects.filter(customUser=customUser, primary=True).first()
              if phone and primary and self.request.session['Phone_object_id'] != phone.id: 
                  
                  raise forms.ValidationError(_('There is another "Primary" Phone already.'), code='invalid')
                  
          except Phone.DoesNotExist:
              pass                  
        if not phone_name and not phone_type and not phone_number:
            raise forms.ValidationError(_('You have to fill out the form!'), code='invalid')
  

Это мое мнение:

class PhoneCreateView(LoginRequiredMixin, CreateView):
    form_class = PhoneForm
    model = Phone
    template_name = 'phones/addPhone.html'
    login_url = reverse_lazy('account_login')
    success_url = reverse_lazy('phonesList')
     
    class Meta:
        readonly = ('customUser', )

    def get_form_kwargs(self):
        kw = super(PhoneCreateView, self).get_form_kwargs()
        kw['request'] = self.request  
        return kw
    
    def get_initial(self):
       
        phone = Phone.create(self.request.user.id)
        form = self.form_class(instance=phone)
        form.instance.customUser = CustomUser.objects.get(id=self.request.user.id)
        
        return {'form': form, }

    def get_context_data(self, **kwargs):
        form_class = PhoneForm
        context = super(PhoneCreateView, self).get_context_data(**kwargs)
        form = self.form_class(instance=self.object)
        context['customUser'] = CustomUser.objects.get(id=self.request.user.id)
        context['form'] = form
        return context
    
    def post(self, request, *args, **kwargs):
        #request.POST['customUser'] = CustomUser.objects.get(id=self.request.user.id)
        customUser = CustomUser.objects.get(id=self.request.user.id)
        print('################ Request.POST: ', request.POST)
        return super().post(request, *args, **kwargs)

    def form_valid(self, form):
        
        form.instance.customUser = CustomUser.objects.get(id=self.request.user.id) 
               
        form.instance.status = 'A' 
        form.instance.status_dt = timezone.now()
        form.instance.at_user = self.request.user.email
        form.instance.at_ip = visitor_ip_address(self.request) 
        form.instance.at_dttm = timezone.now()
        form.instance.at_action = 'Create Phone number'
        
        messages.success(self.request, _('Your Phone Number has been registered.'))
        return super(PhoneCreateView, self).form_valid(form)

    def form_invalid(self, form, **kwargs):
        
        messages.error(self.request,  _('Your Phone record has errors.'))
        
        return self.render_to_response(
            self.get_context_data(request=self.request, form=form))

1 Ответ

0 голосов
/ 23 июня 2020

Мне пришлось изменить метод get_context_data в моем представлении следующим образом:

def get_context_data(self, **kwargs):
        #Use this to add extra context.#
        context = super(PhoneCreateView, self).get_context_data(**kwargs)
        form = self.form_class(instance=self.object)
        form.instance.customUser = CustomUser.objects.get(id=self.request.user.id)
        
        return context
...