djangoautofillmodelformgeneric-foreign-key

forms.py creating forms with ForeignKey model. A store should only be able to add products to its own store. (Django)


A store should only be able to create a product for himself, not for other stores.

models.py

from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
from django.dispatch import receiver

class Store(models.Model):
    name = models.CharField(max_length=100)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    slug = models.SlugField(unique=True, blank=False, null=False)


class Product(models.Model):
    store = models.ForeignKey(Store, on_delete=models.CASCADE, null=False, blank=False)
    name = models.CharField(max_length=200)
    price = models.FloatField()
    image = models.ImageField(null=True, blank=True)

forms.py

from .models import Store, Product
from django import forms

class AddProductForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        user = kwargs.pop('user', None)
        super().__init__(*args, **kwargs)

        # restrict the queryset of 'Store'
        self.fields['store'].queryset = self.fields['store'].queryset.filter(
            owner=user)

    class Meta:
        model = Product
        fields = ('store', 'name', 'price', 'image',)

        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Name of your product'}),
            'price': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Price of your product'}),
            'image': forms.FileInput(attrs={'class': 'form-control'}),
        }

In my views.py file, I have tried different stuff, but nothing worked, so I keep it there so you know what I have tried.

views.py

from django.shortcuts import render, redirect
from django.urls.base import reverse
from django.contrib.auth.models import User, Group
from django.contrib.auth import authenticate, login
from .models import Product, Store
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView


class AddProductView(CreateView):

    model = Product
    form_class = AddProductForm
    template_name = 'app1/add-product.html'



    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs


    def form_valid(self, form):
        form.instance.owner = self.request.user
        if Store.objects.filter(owner=self.request.user).exists():
            self.store = Store.objects.filter(Store__owner=self.request.user)

            form = form.cleaned_data
            form['store'] = self.store
            
            return super().form_valid(form)
            
        else:
            return super().form_invalid(form)

    

    
    def form_invalid(self, form):
        return super().form_invalid(form)

    
    def get_context_data(self, **kwargs):
        pass

    
    def get_success_url(self):
        return reverse('store', kwargs={'slug': self.object.store.slug})

I don't know what to google for, I have tried these topics:

How to autofill variable with foreign key in django form?

Django - Forms - autofill & hide foreign key field


Solution

  • Just an example of the imports in views.py

    from django.shortcuts import render, redirect
    from django.urls.base import reverse
    from django.contrib.auth.models import User, Group
    from django.contrib.auth import authenticate, login
    from .models import Product, Store
    from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
    

    In the views.py just add this

    class AddProductView(CreateView):
    
        model = Product
        form_class = AddProductForm
        template_name = 'app1/add-product.html'
    
    
    
      # add this code |
      #               V
    
        def get_initial(self):
            if Store.objects.filter(owner=self.request.user).exists():
                user = self.request.user
                initial = super(AddProductView, self).get_initial()
                initial['store'] = Store.objects.get(owner=user)
                return initial    
    
    
        ...
    

    Make sure you edit it for your model names and needs as well.


    If you want to hide it, check out this post Change a Django form field to a hidden field