Elisha512 Elisha512 - 3 months ago 28
Python Question

Django forms selecting data based on request user

I am developing a django application which has a form for creating ingredients. The form contains a dropdown for selecting Recipes. When a user creates an ingredient, in the dropdown, I want that only those recipes should appear that are created by the same user.

Here is my code:

#forms.py
class IngredientForm(forms.ModelForm):
primal = forms.BooleanField()
class Meta:
model = Ingredient
fields = ('recipe_id', 'title', 'instructions', 'rules')
#models.py
class Recipe(models.Model):
user = models.ForeignKey('auth.User')
title = models.CharField(max_length=500)
description = models.TextField(max_length=500)
rules = models.TextField(max_length=500,blank=True)
def __str__(self):
return self.title
class Ingredient(models.Model):
user = models.ForeignKey('auth.User')
recipe_id = models.ForeignKey(Recipe, on_delete=models.CASCADE)
title = models.CharField(max_length=500)
instructions = models.CharField(max_length=500)
rules = models.TextField(max_length=500,blank=True)
primal = models.CharField(default='0',max_length=500,blank=True)
def __str__(self):
return self.title

#views.py

def create_ingredient(request):
if request.method == 'POST':
form = IngredientForm(request.POST)
if form.is_valid():
current_user = request.user
data = form.cleaned_data
ingredient_data=Ingredient.objects.create(user=current_user, recipe_id=data['recipe_id'],title=data['title'], primal=data['primal'], instructions=data['instructions'], rules=data['rules'])
ingredient_data.save()
ingredient = Ingredient.objects.get(pk = ingredient_data.pk)
return redirect('ingredient_detail', pk=ingredient.pk)
else:
messages.error(request, "Error")
return render(request, 'create_ingredient.html', {'form': IngredientForm })


The problem is that right now, when the user tries to select a recipe, the recipes created by all users of the site appear in the 'recipe_id' dropdown. He should only be able to see recipes in the dropdown that are created by himself. Any ideas how to do it?

UPDATE FROM ANSWER:

If I use this:

...
if request.method == 'POST':
form = IngredientForm(current_user=request.user, request.POST)
if form.is_valid():
...


it gives me this syntax error:
non-keyword arg after keyword arg
in this line
form = IngredientForm(current_user=request.user, request.POST)


UPDATE#2:

If I use:

...
if request.method == 'POST':
form = IngredientForm( request.POST,current_user=request.user)
if form.is_valid():
...


It gives me error:
__init__() got multiple values of argument 'current.user'


If I use:

...
if request.method == 'POST':
form = IngredientForm( request.POST)
if form.is_valid():
...


It gives me error:
'QueryDict' object has no attribute 'id'


UPDATE # 3:

After implementing the latest update from answer. It gives me error
name 'current_user' is not defined

in the following piece of code:

def create_ingredient(request):
form = IngredientForm(current_user=request.user)

Answer

In the model form you can do this:

class IngredientForm(ModelForm):
    primal = forms.BooleanField()
    class Meta:
        model = Ingredient
        fields = ('recipe_id', 'title', 'instructions', 'rules')

    def __init__(self, current_user, *args, **kwargs):
        super(IngredientForm, self).__init__(*args, **kwargs)
        self.fields['recipe_id'].queryset = self.fields['recipe_id'].queryset.filter(user=current_user.id)

then instantiate the form like so

form = IngredientForm(current_user=request.user)

EDIT #1:

Passing in the user to the POST request form:

if request.method == "POST":
    form = IngredientForm(request.POST, current_user=request.user)
    if form.is_valid():
        ....

EDIT #2:

Try changing the init decleration to what is below and pop the user from the kwargs:

def __init__(self, *args, **kwargs):
    current_user = kwargs.pop('current_user', None)
    super(IngredientForm, self).__init__(*args, **kwargs)
    if current_user:
        self.fields['recipe_id'].queryset = self.fields['recipe_id'].queryset.filter(user=current_user.id)

I think this might solve your problems, leave the rest of the code the same as my answer above (where you create the forms)