How to attach foreign key associated with the multiple models to submit one form

How can in create inline formset which share the same foreign key using function base views. I don’t want to keep selecting product title(which is the FK to other forms) because am using two forms with linked to one Foreign key#

i want to implement this https://www.letscodemore.com/blog/django-inline-formset-factory-with-examples/ in function base views

I have these 3 models

#product model

class Product(models.Model): 
    title = models.CharField(max_length=150) 
    short_description = models.TextField(max_length=100)

    def __str__(self):
        return self.title

*Image model*
class Image(models.Model): 
    product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True) 
    image = models.ImageField(blank=True, upload_to='images')
    
    def __str__(self):
        return self.product.title


*variant model*
class Variant(models.Model):
     
    product = models.ForeignKey( Product, on_delete=models.CASCADE) 
    size = models.CharField(max_length=100) 
    quantity = models.PositiveIntegerField(default=1) 
    price = models.DecimalField(max_digits=12, decimal_places=2)


    def __str__(self):
        return self.product.title

Forms


from django import forms from 
django.forms import inlineformset_factory

from .models import ( Product, Image, Variant)

class ProductForm(forms.ModelForm):

    class Meta:
        model = Product
        fields = '__all__'
        widgets = {
            'title': forms.TextInput(
            attrs={ 'class': 'form-control'} ), 'short_description': forms.TextInput(
            attrs={'class': 'form-control'}),
    }

class ImageForm(forms.ModelForm):

    class Meta:
        model = Image
        fields = '__all__'

class VariantForm(forms.ModelForm):

    class Meta:
        model = Variant
        fields = '__all__'
        widgets = {
        'size': forms.TextInput(attrs={'class': 'form-control'} ),
        'quantity': forms.NumberInput(attrs={'class': 'form-control'}),
        'price': forms.NumberInput(attrs={ 'class': 'form-control'}),
    }

VariantFormSet = inlineformset_factory( Product, Variant, form=VariantForm, extra=1, can_delete=True, can_delete_extra=True ) 

ImageFormSet = inlineformset_factory( Product, Image, form=ImageForm,extra=1, can_delete=True, can_delete_extra=True )

Views

**Views**
from django.shortcuts import render, redirect 
from django.contrib import messages 
from .forms import (ProductForm, VariantFormSet, ImageFormSet) 
from .models import (Image, Product, Variant)

#create product
def create_product(request):
    
    if method.request == 'POST': 
        form = ProductForm(request.POST)
        if form.is valid():
              form.save()
        else: form = ProductForm() 
    return redirect('product:products')

What i tried

How can in create inline formset which share the same foreign key using function base views. I don’t want to keep selecting product title(which is the FK to other forms) because am using two forms with linked to one Foreign key#

What i tried

**Views**
from django.shortcuts import render, redirect 
from django.contrib import messages 
from .forms import (ProductForm, VariantFormSet, ImageFormSet) 
from .models import (Image, Product, Variant)

#create product
def create_product(request):
    
    if method.request == 'POST': 
        form = ProductForm(request.POST)
        if form.is valid():
              form.save()
        else: form = ProductForm() 
    return redirect('product:products')

What i tried

#Attach Image and variant to the product

when submitting this form, the VariantForm should get FK(product title field) from the ImageForm FK which has already been selected in the django template

#Attach  product image and variation to product
def add_image_and_variant(request):
    
    if method.request == 'POST': 
        
        image_form = ImageForm(request.POST,request == 'FILES') 
        var_form = VariantForm(request.POST)
        if image_form.is valid() and var_form():
            
            image_instance =image_form.save()
            var = var_form(commit = False)
            var =  var(image_instance.title)
            var.save()
        else: 
            image_form = ImageForm() 
            var_form = VariantForm() 
        return redirect('product:products')
    return render(request,'product_var.html',{'image_form':image_form,:var_form})

The first thing I noticed - and it might be a copy/paste issue - is that you don’t have your Meta class definitions indented within the Form classes.

Please confirm that your code is indented properly.

1 Like

I have edited.
if you have solution kindly assist

I’m not sure what you’re asking for here.

You have a base model, Product.

You have two independent formsets, one each for the Variant and Image models.

You’re showing one view for create_product. You’re showing a separate view add_image_and_variant. This view is creating instances of forms.

I don’t see in any of this where you’re using your formsets. So it’s not clear to me what you’re trying to achieve.

If you’re not comfortable with formsets yet, I would recommend simplifying what you’re trying to do - maybe just try with one formset so that you gain some understanding of how formsets work. It would be easiest for you to cut this down to a smaller example - that may help reduce some of the complexity.

If you’re trying to replicate what that blog post shows, then I would suggest you start out by implementing exactly what is in the post, to where you understand what everything is doing, and then working in your modifications from there.

Thank you for your response @KenWhitesell
I haven’t started using formset yet since i got stuck on how to pass image foreign key to variant foreign key.
I need the user to select the product item once on one form(which has image and variant form) since both share the same FK.

Everything appears ok at first glance up to and including the first of these two lines.

It’s the second line which isn’t correct.

var is an instance of Variant. It has a field named product. It’s that field that you want to set to the value of product that is in your instance of Image.

i get this error Variant object is not callable

Let’s break this down then. You have:

What does the function call var_form(commit=False) return? (What is var being set to? Or, to phrase this question differently, what is the data type of var after this line?)

See Creating forms from models | Django documentation | Django if necessary.

1 Like

Thank alot @KenWhitesell. i found a solution for this

var = var_form(commit = False)
var.product = product.title
var.save()