web-dev-qa-db-fra.com

ModelForm avec OneToOneField dans Django

J'ai deux modèles dans Django qui sont liés à un OneToOneField (PrinterProfile et PrinterAdress). J'essaie de faire un formulaire avec PrinterProfileForm, mais pour une raison quelconque, il ne passe PAS les champs PrinterAddress dans le formulaire (il n'est pas rendu par Django "magic" dans le modèle).

Que dois-je faire pour que mon PrinterProfileForm inclue également les champs de PrinterAddress (son OneToOneField) connexe?

Merci beaucoup

class PrinterProfile(TimeStampedModel):
    user = models.OneToOneField(User)
    phone_number = models.CharField(max_length=120, null=False, blank=False)
    additional_notes = models.TextField()
    delivery = models.BooleanField(default=False)
    pickup = models.BooleanField(default=True)


# The main address of the profile, it will be where are located all the printers.    
class PrinterAddress(TimeStampedModel):
    printer_profile = models.OneToOneField(PrinterProfile)
    formatted_address = models.CharField(max_length=200, null=True)
    latitude = models.DecimalField(max_digits=25, decimal_places=20)  # NEED TO CHECK HERE THE PRECISION NEEDED.
    longitude = models.DecimalField(max_digits=25, decimal_places=20)  # NEED TO CHECK HERE THE PRECISION NEEDED.
    point = models.PointField(srid=4326)

    def __unicode__(self, ):
        return self.user.username

class PrinterProfileForm(forms.ModelForm):
    class Meta:
        model = PrinterProfile
        exclude = ['user']
27
cyberjoac

Vous devez créer un deuxième formulaire pour PrinterAddress et gérer les deux formulaires dans votre vue:

if all((profile_form.is_valid(), address_form.is_valid())):
    profile = profile_form.save()
    address = address_form.save(commit=False)
    address.printer_profile = profile
    address.save()

Bien sûr, dans le modèle, vous devez afficher les deux formulaires sous un seul <form> tag :-)

<form action="" method="post">
    {% csrf_token %}
    {{ profile_form }}
    {{ address_form }}
</form>
32
catavaran

Complétant le réponse acceptée :

Si vous avez des méthodes de nettoyage personnalisées, vous devez ajouter un cas try/except. Pour l'exemple présenté si address avait une méthode clean() pour valider quelque chose que vous deviez changer en:

def clean(self):
    try:
        printer_profile = self.printer_profile 
    except ObjectDoesNotExist:
        pass
    else:
        ...code to validate address...
1
NBajanca