Search code examples
pythondjangoformstemplatesmodels

Hiding foreign key fields from ModelForms in Django Template


Essence in the following. I have a few different Magazine. And AutoForm from template shows all Articles and all Authors for possible selection (not only from current Magazine). How to restrict this choice of author a for article only from the current magazine? Can I do this using only the Template? If not, then how?

models.py

class Magazine(models.Model):
    Name = models.CharField(max_length=200)

class Article(models.Model):
    Name = models.CharField(max_length=200)
    Magazine = models.ForeignKey(Magazine)

class Author(models.Model):
    Name = models.CharField(max_length=200)
    Magazine = models.ForeignKey(Magazine)

class Sets(models.Model):
    Name = models.CharField(max_length=200)
    Magazine = models.ForeignKey(Magazine)
    Aut = models.ManyToManyField(Author, null=True, blank=True)
    Set = models.ForeignKey(Article, null=True, blank=True)

forms.py:

class MagazineForm(ModelForm):
    class Meta:
        model = Magazine
        fields = {'Name'}

class ArticleForm(ModelForm):
    class Meta:
        model = Article
        fields = {'Name'}

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = {'Name'}

class SetsForm(ModelForm):
    class Meta:
        model = Sets
        fields = {'Name', 'Set', 'Aut'}

views.py

def building_details(request, magazine_id):
    sets_form = SetsForm
    args = {}
    args.update(csrf(request))
    args['magazine'] = Magazine.objects.get(id=magazine_id)
    args['article'] = Article.objects.filter(Magazine=magazine_id)
    args['author'] = Author.objects.filter(Magazine=magazine_id)
    args['sets'] = Sets.objects.filter(Magazine=magazine_id)
    args['setform'] = sets_form
    return render_to_response('building.html', args)

Template

<form action='/add/{{ magazine.id }}/' method='post'>
{% csrf_token %}
{{ setform }}
<input type='submit' class='button' value="Добавить">
</form>
</div>

Maybe somewhere in this entry there are errors (I briefly edited, removing not playing a role here, essentially). In General I have everything working right, except that all objects are displayed, instead of only having the current.


Solution

  • Sounds like you are trying to restrict the options in the ForeignKey selector based on some criteria.

    This means you need to override some of the details in the forms __init__ method:

    class SetsForm(ModelForm):
        class Meta:
            model = Sets
            fields = {'Name', 'Set', 'Aut'}
    
        def __init__(self, *args, **kwargs):
            articles = Article.objects.filter(Magazine=kwargs.pop('magazine_id'))
            super(SetsForm, self).__init__(*args, **kwargs)
            self.fields['articles'] = forms.ModelChoiceField(
                queryset=articles ,
                label="Articles",
            )
    

    Then call your form like so:

    sets_form = SetsForm(magazine_id=magazine_id)