Amartya Gaur
Amartya Gaur

Reputation: 705

How to create a form for dealing with multiple django model objects

So I have a model Post with the following definition:

class Post(models.Model):
    post_body = models.TextField()
    user = models.ForeignKey(
        to=User,
        on_delete=models.CASCADE
    )
    published = models.BooleanField(
        default=False
    )
    schedule = models.DateTimeField(
        default=timezone.now
    )

I have created a form in HTML template allowing the user to select the posts he want to send to another website or social media account. Like so:

<form>
    <table class="table table-hover">
        <thead>
        <tr>
            <th scope="col">Select</th>
            <th scope="col">Post Body</th>
            <th scope="col">Published?</th>
            <th scope="col">Schedule (Editable)</th>
        </tr>
        </thead>
        <tbody>
        {% for post in posts %}
            <tr>
                <td>
                    <div class="form-group">
                        <input type="checkbox" value="{{ post.id }}">
                    </div>
                </td>
                <td>{{ post.post_body }}</td>
                <td>{{ post.published }}</td>
                <td>
                    <div class="form-group">
                        <input type="datetime-local" class="form-control" name="schedule" value="{{ post.schedule|date:"Y-m-d\TH:i" }}">
                    </div>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
    <button class="btn btn-primary" type="submit">Post</button>
</form>

I want to create a Form in the forms.py in order to process this information (i.e. know which all posts were selected) and then perform further actions (calling other APIs in order to publish these to other sites), also since the field schedule is editable, I want to be able to save that as well. Please help as I cannot think of a possible form for this.

Upvotes: 0

Views: 188

Answers (3)

Daniel Backman
Daniel Backman

Reputation: 5241

One way to solve it is to use ModelMultipleChoiceField

Here is the structure I've used for similar scenarios:

class SelectPostsForm(forms.Form):
    posts = forms.ModelMultipleChoiceField(
        queryset=Post.objects.none(), widget=forms.CheckboxSelectMultiple)

    def __init__(self, filtered_post_queryset, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['posts'].queryset = filtered_post_queryset

    def get_posts(self):
        return self.cleaned_data.get('posts')


    # Example usage
    form = SelectPostsForm(Post.objects.all(), data=request.data)
    if form.is_valid():
       selected_posts = form.get_posts()
       # Process posts...

It will probably work directly with the html code you showed if you add name="posts" the the input.

The "filtered_post_queryset" you can provide via the view if you need to do this on a filtered/restricted queryset. Data will then be properly validated via form.is_valid() against the filtered queryset.

Upvotes: 1

rafaljusiak
rafaljusiak

Reputation: 1090

If you want to handle multiple objects of the same type through forms, then you should try with formsets - https://docs.djangoproject.com/en/3.0/topics/forms/formsets/

There's a lot of other options, but I think that formset will cover your needs.

EDIT: Please take it as a guide only:

# forms.py


class PostForm(forms.ModelForm):
    is_selected = forms.BooleanField(default=False)

    class Meta:
        model = Post
        fields = ("is_selected", "other", "model" "fields")


PostFormSet = modelformset_factory(Post, form=PostForm)
# views.py

class PostView(generic.View):
    def get(self, request, *args, **kwargs):
        posts = Post.objects.all()  # get your Post queryset
        formset = PostFormSet(queryset=posts)
        # ...
        return response

    def post(self, request, *args, **kwargs):
        formset = PostFormSet(request.POST)
        for form in formset.forms:
            if form.is_valid() and form.cleaned_data.get("is_selected"):
                # here you can save your instance and/or write logic 
                # to process gathered information
        # ...
        return response  

Upvotes: 1

Hashir
Hashir

Reputation: 400

You want all your "posts" to render by "one form()" then manipulate the selected posts. Formsets are used for this in django. Although there are many types but any simple formset will get your work done.

Please visit django documentation for implementation: https://docs.djangoproject.com/en/3.0/topics/forms/formsets/

For quick and easy understanding visit this: https://www.geeksforgeeks.org/django-formsets/

Upvotes: 0

Related Questions