Reputation: 705
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
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
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
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