'How to save foreign key data using forms.py?

urls.py

...
path('restaurant/menu/', r_view.Menu, name='menu'),
...

menu.html

<form method="POST" id="menuForm" autocomplete="off" action="" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="form-inline">
            <div class="form-group mb-4">
                {{ form.item|as_crispy_field }}
            </div>
            <div class="form-group mb-4">
                {{ form.itemImage|as_crispy_field }}
            </div>
            <div class="form-group mb-4">
                {{ form.price|as_crispy_field }}
            </div>
            <div class="form-group mb-4">
                {{ form.category|as_crispy_field }}
            </div>
        </div>

        <button type="submit" class="col-md-12 myBtn">Submit</button>
    </form>

views.py

def Menu(request, restaurantID):
    restaurant = get_object_or_404(Restaurant_Account, restaurantID=restaurantID) 
    form = MenuForm()

    if request.method == 'POST':
        form = MenuForm(request.POST, request.FILES)
        if form.is_valid():
            instance = form.save(commit=False)
            instance.restaurant = restaurant
            instance.save()
            messages.success(request, "Saved successfully!")
            return redirect('r_index')
            
    context = {'form':form}
    return render(request, 'restaurant/menu.html', context)

forms.py

class MenuForm(forms.ModelForm):
    restaurantID = Restaurant_Account.objects.filter(restaurantID='restaurantID')
    item = forms.CharField(required=True)
    itemImage = forms.ImageField(required=False, label='Item image')
    price = forms.DecimalField(required=True)
    category = forms.ChoiceField(choices=CATEGORY)
    class Meta:
        model = Menu
        fields = ('item', 'itemImage', 'price', 'category')

models.py

class Restaurant(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_restaurant = models.BooleanField(default=True)
    restaurantID = models.AutoField(primary_key=True)
    name = models.CharField(max_length=200)
    isActive = models.BooleanField(default=True)
    image = models.ImageField(upload_to='images/', blank=True)
    website = models.URLField(blank=True, unique=False)
    country = models.CharField(max_length=50)

    def __str__(self):
        return self.user.username

class Menu(models.Model):
    menuID = models.AutoField(primary_key=True)
    restaurantID = models.ForeignKey(Restaurant_Account, on_delete=models.CASCADE, default=None)
    item = models.CharField(max_length=100)
    itemImage = models.ImageField(upload_to='images/', blank=True)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    category = models.CharField(
        max_length=20,
        choices=[('', 'Choose category'),('Appetizer', 'Appetizer'),('Entree', 'Entree'),('Drink', 'Drink'),('Dessert', 'Dessert'), ('Side', 'Side')])
    
    def __str__(self):
        return self.item  

I'm new to Django.

I made a form for saving menu data. If the user fills the form and click the submit button every data should be saved in the Menu table. I have no idea how to save restaurantID, which is a foreign key that refers to the Restaurant table, automatically. (By automatically I mean without the user entering input) Can somebody help me with this?



Solution 1:[1]

You haven't need to do all these things, if you have made restaurantID a foreign key while defining the model that is Menu, django itself handles it.

Below code might work for you:

forms.py

class MenuForm(forms.ModelForm):
    item = forms.CharField(required=True)
    itemImage = forms.ImageField(required=False, label='Item image')
    price = forms.DecimalField(required=True)
    category = forms.ChoiceField(choices=CATEGORY)
    class Meta:
        model = Menu
        fields = ('item', 'itemImage', 'price', 'category')

views.py

def menu(request):
    if request.method == 'POST':
        form = MenuForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            messages.success(request, "Saved successfully!")
            return redirect('r_index')
    else:
        form=MenuForm()
    return render(request, 'restaurant/menu.html', {'form':form})

optional: You also don't need to write this line menuID = models.AutoField(primary_key=True) in Menu model, as django makes id column by default for AutoField.

Update:

Make your models.py in this way:

MY_CHOICES=[
('', 'Choose category'),
('Appetizer', 'Appetizer'),
('Entree', 'Entree'),
('Drink', 'Drink'),
('Dessert', 'Dessert'), 
('Side', 'Side')
    
]
class Restaurant(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    is_restaurant = models.BooleanField(default=True)
    name = models.CharField(max_length=200)
    isActive = models.BooleanField(default=True)
    image = models.ImageField(upload_to='images/', blank=True)
    website = models.URLField(blank=True, unique=False)
    country = models.CharField(max_length=50)

    def __str__(self):
        return self.user.username

class Menu(models.Model):
    restaurant= models.ForeignKey(Restaurant, on_delete=models.CASCADE, default=None)
    item = models.CharField(max_length=100)
    itemImage = models.ImageField(upload_to='images/', blank=True)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    category = models.CharField(
        max_length=20,
        choices=MY_CHOICES)
    
    def __str__(self):
        return self.item  

Remove your AutoField, django by default make id which is primary key. Don't forget to run makemigrations and migrate, after doing this, if it still gives error, so comment your all models and then run.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1