1

I've been trying to solve this problem for a couple of days now, getting quite desperate. See the commented out code snippets for some of the things I've tried but didn't work.

Problem: How can I limit the values in the category field of the IngredientForm to only those belonging to the currently logged in user?

enter image description here

views.py

@login_required
def apphome(request):
    IngrFormSet = modelformset_factory(Ingredient, extra=1, fields=('name', 'category'))

    # Attempt #1 (not working; error: 'IngredientFormFormSet' object has no attribute 'fields')
    # ingrformset = IngrFormSet(prefix='ingr', queryset=Ingredient.objects.none())
    # ingrformset.fields['category'].queryset = Category.objects.filter(user=request.user)

    # Attempt #2 (doesn't work)
    # ingrformset = IngrFormSet(prefix='ingr', queryset=Ingredient.objects.filter(category__user_id = request.user.id))

models.py:

class Category(models.Model):
    name = models.CharField(max_length=30, unique=True)
    user = models.ForeignKey(User, null=True, blank=True)       

class Ingredient(models.Model):
    name = models.CharField(max_length=30, unique=True)
    user = models.ForeignKey(User, null=True, blank=True)
    category = models.ForeignKey(Category, null=True, blank=True)
    counter = models.IntegerField(default=0)

forms.py:

class IngredientForm(ModelForm):
    class Meta:
        model = Ingredient 
        fields = ('name', 'category')

UPDATE: I've made some progress but the solution is currently hard-coded and not really usable:

I found out I can control the categoryform field via form class and then pass the form in the view like this:

#forms.py
class IngredientForm(ModelForm):
    category = forms.ModelChoiceField(queryset = Category.objects.filter(user_id = 1))

    class Meta:
        model = Ingredient 
        fields = ('name', 'category')

#views.py
IngrFormSet = modelformset_factory(Ingredient, form = IngredientForm, extra=1, fields=('name', 'category'))

The above produces the result I need but obviously the user is hardcoded. I need it to be dynamic (i.e. current user). I tried some solutions for accessing the request.user in forms.py but those didn't work.

Any ideas how to move forward?

finspin
  • 4,021
  • 6
  • 38
  • 66

2 Answers2

4

You don't need any kind of custom forms. You can change the queryset of category field as:

IngrFormSet = modelformset_factory(Ingredient, extra=1, fields=('name', 'category'))
IngrFormSet.form.base_fields['category'].queryset = Category.objects.filter(user__id=request.user.id)
Aamir Rind
  • 38,793
  • 23
  • 126
  • 164
  • Thanks for the answer. The problem is that I don't have just one form on the page so I need to use modelformset_factory. I did this: `IngrFormSet = modelformset_factory(Ingredient, form = IngredientForm(user = request.user), extra=1, fields=('name', 'category'))` in the view but it gives me an error: `__init__() takes at least 2 arguments (1 given)`. – finspin Jan 08 '13 at 07:55
  • @finspin I have again updated my answer. This should work. You don't need any custom form. You can directly overwrite the queryset using `IngrFormSet.form.base_fields` which contains all fields. I have also tested it and it works. – Aamir Rind Jan 08 '13 at 13:03
  • Thanks, that's exactly what I was needed! I didn't know about base_fields. Nice and simple solution. Will award you bounty as soon as the system allows (in 3 hours). – finspin Jan 08 '13 at 18:38
0
Category.objects.filter(user=request.user)

returns a list object for the initial value in your form which makes little sense.

Try instead

Category.objects.get(user=request.user)

or

Category.objects.filter(user=request.user)[0]
Philipp Zedler
  • 1,660
  • 1
  • 17
  • 36
  • Actually, I think I'm probably misusing the `initial` parameter here. What I'm trying to achieve is to filter the values in the `category` form field (drop-down) to the ones belonging to the current user. Attempt #2 (see the above view code sample) is probably quite close to what I'm trying to do but it still doesn't work. – finspin Jan 06 '13 at 16:51
  • Aha! I misunderstood your question. You can either use a [Model formset](https://docs.djangoproject.com/en/1.4/topics/forms/modelforms/#model-formsets) and provide an instance argument like [here](http://stackoverflow.com/a/11494192/1378264), or you create a [ModelForm](https://docs.djangoproject.com/en/1.4/topics/forms/modelforms/) where you define "category" as a [ModelChoiceField](https://docs.djangoproject.com/en/1.4/ref/forms/fields/#modelchoicefield) with a certain `queryset`. – Philipp Zedler Jan 06 '13 at 20:48
  • I think I need to stick with modelformset since I have several forms on the same page. I tried to pass the instance argument as suggested in the answer you posted but I'm getting an error: `__init__() got an unexpected keyword argument 'instance'`. I also tried another approach (see my updated question) with no luck. – finspin Jan 07 '13 at 21:42