MultipleChoiceField django python, impossible display datas in the template - python

I have big problem, I use MultipleChoic Field into django for "input multiselect",
a user at the possibility of make many choices via the "input select multiple"
I explain to you :
I use this Package : https://pypi.org/project/django-multiselectfield/
this is my model :
class Profil(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,)
skill = MultiSelectField(max_length=500, null=True, blank=True, choices=Skillz)
board = MultiSelectField(max_length=500, null=True, blank=True, choices=Boardz)
this is my form :
class ProfilForm(forms.ModelForm):
skill = forms.MultipleChoiceField(required=False, widget=forms.SelectMultiple, choices=Skillz)
board = forms.MultipleChoiceField(required=False, widget=forms.SelectMultiple, choices=Boardz)
this is my datas of the choices (used in models Profil and form ProfilForm):
Boardz = (
('Reddit', 'reddit.com'),
('Discord', 'discord.com'),
('Twitter', 'twitter.com'),
)
Skillz = (
('Python', 'PythonDjango'),
('Rust', 'RustRocket'),
('Ruby', 'RubyOnRails'),
)
Now the concern problem is views.py and my template.html
<!-- this is what I want with my datas -->
<select multiple class="form-control" id="id_board">
<option>reddit.com</option>
<option>discord.com</option>
<option>twitter.com</option>
</select>
<select multiple class="form-control" id="id_skillz">
<option>PythonDjango</option>
<option>RustRocket</option>
<option>RubyOnRails</option>
</select>
<input type="submit" value="Save">
Into the views.py (which is surely wrong) :
def GetDatasForRegisterForm(request):
form = ProfilForm()
return render_response(request, "registration/register.html",{'form': form})
template.html :
I'm totally lost for display my data choices in select multiple for the user, please guys, how make ?

Update : It's good, I have what I wanted, here is for your members of stack overflow, my solution :
class ProfilForm(forms.ModelForm):
skill = forms.MultipleChoiceField(widget=forms.SelectMultiple, choices=Skillz) # skillz and boardz into choices.py
board = forms.MultipleChoiceField(widget=forms.SelectMultiple, choices=Boardz)
class Meta:
model = Profil
fields = ('skill', 'board',)
in views.py > form = ProfilForm(), return render..
{% for value,text in form.board.field.choices %}
<option value="{{ value }}">{{ text }}</option>
{% endfor %}

This is how i go about generating my template and views.py when dealing with forms.
First here you have defined your form ProfilForm one quick way to know the html generated in your form when your views look like
def GetDatasForRegisterForm(request):
form = ProfilForm()
return render_response(request, "registration/register.html",{'form': form})
In your templates you can just do
<form method="POST" action="<your_action>">
{{ csrf_token }}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
Now when you render this django will create a basic HTML for you, based on model specified. You can copy the HTML and customize the styling and populate the values by accessing the form field values.
Now you haven't asked about how to save this form. But let me do that anyway.
We are going to handle the form post in the same controller which will look like.
def GetDatasForRegisterForm(request):
form = ProfilForm(request.POST or None)
if request.method == "POST" and form.is_valid():
form.save()
return redirect("/<sucess_page>")
return render_response(request, "registration/register.html",{'form': form})
In the view here, i am loading the form with POST data if it exists and checking if the form is valid in the POST and saving it as well. You can where to lead the page to if it is success or error.

Related

How to loop through a form and add same form in django if we click add more button and store that in django

What I really want to do is , if a user click on "ADD more" button then a same form repeat itself and the values should store in database, if he/she doesn't click of that button then only the values from first form should be stored.
I am not able to get this, I just created a form , and a table in database for those details but can't loop though the form neither in data.
please help.
This is the form and the button:
This is the model.py code:
from django.db import models
class experience(models.Model):
company_name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
startdate = models.Datefield(default = 01-01-2020)
lastdate = models.DateField(default = 01-01-2020)
profile = models.CharField(max_length=100)
description = models.TextField(max_length = 250)
This is the views.py code:
from django.shortcuts import render, redirect
import requests
from django.contrib.auth.models import User, auth
# Create your views here.
def profile(request):
return render(request, 'profile.html')
Unfortunately, there's no built-in way (as far as I know) in Django to do that without Javascript, but here's an approach:
HTML:
<div class="container" id="experiencesContainer">
<form method='POST' name='experienceForm'>
{{form.as_p}}
</form>
<form method='POST' name='experienceForm'>
{{form.as_p}}
</form>
<button type="button" id="addMoreButton">Add more</button>
<button type="submit">Save Changes</button>
</div>
Django POST method:
# Get a list of submitted forms
experiences = request.POST.getlist('experienceForm')
for experience in experiences:
# this is how you loop throuh every form
experience.get('company_name)
Your javascript something like:
// clonning his childs as well
let cloneForm = document.querySelector('form[name=experienceForm]').cloneNode(true);
document.querySelector('div#experiencesContainer').appendChild(cloneForm);
// see this https://www.w3schools.com/jsref/met_node_clonenode.asp
Of course this code is not tested but I've done this in several projects before, hope it works!
A simple way would be to request the same view from the "Add", just make sure your form view saves the data when request method is POST.
<form action="{% url 'your-form-url' %}" method="GET">
{% csrf_token %}
<input type="submit" value="Add">
</form>
one other way to repeat forms would be using formsets. Formsets allow you to repeat the same form 'extra' times. Check out the documentation for more about this.
def repeat_form(request):
ExpFormSet = formset_factory(ExperienceForm, extra=3)
#extra defines the no. of forms you want to display
if request.method == 'POST':
formset = ExpFormSet(request.POST, request.FILES)
if formset.is_valid():
# do something with the formset.cleaned_data
#loop through each form in the formser
for form in formset.cleaned_data:
obj = form.save()
else:
formset = ExpFormSet()
return render(request, 'exp_form.html', {'formset': formset})
The corresponding template should be:-
<form method="post">
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }}
{% endfor %}
</form>
Make sure you add form.management_form. Using the combination of the above might solve your problem of taking and saving several inputs.

How can i use more different forms in the same Django template?

In my project, i have a template where i'm trying to put two forms for different use cases. I've never come across this problem before, so i don't really know where to go from here to use two forms in the same page.
At first i thought of creating another view to handle each form, but i think that this solution would create problems with the rendering of my templates, other than not being sustainable if i should have this problem again with another template.
After making some research, i found a solution but it works for class based views, but i'd like to avoid that since my view is already a function based view, and i would have to make a lot of changes in my code.
Would it be possible to solve this problem with a function based view? Every advice is appreciated
First field
class FirstForm(forms.ModelForm):
firstfield = forms.CharField()
secondfield = forms.CharField()
class Meta:
model = MyModel
fields = ("firstfield", "secondfield")
def save(self, commit=True):
send = super(FirstForm, self).save(commit=False)
if commit:
send.save()
return send**
Second Form
class SecondForm(forms.ModelForm):
firstfield = forms.FloatField()
secondfield = forms.Floatfield()
thirdfield = forms.CharField()
class Meta:
model = MyModelTwo
fields = ("firstfield", "secondfield", "thirdfield")
def save(self, commit=True):
send = super(SecondForm, self).save(commit=False)
if commit:
send.save()
return send
Template
<h3> First Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
<h3> Second Form </h3>
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button type="submit" class="btn btn-danger" style="background-color: red;">SUBMIT</button>
</form>
EDIT: my view:
def myview(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = FirstForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
send = form.save()
send.save()
messages.success(request, f"Success")
# if a GET (or any other method) we'll create a blank form
else:
form = FirstForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
This answer is a bit general because you haven't included your view function. You can add each of these forms to your view's context. Something like this:
views.py
...
from .forms import FirstForm, SecondForm
...
def some_view(request):
context = {
'first_form': FirstForm(request.POST or None),
'second_form': SecondForm(request.POST or None)
}
return render(request, "app/some_template.html", context)

django_countries does not display in the form on template

I used {{ form }} as seen here
template.html
<h4>Change your details</h4><br>
<form id="edit_form" method='post'>
{% csrf_token %}
{{ form }}
<div class='section group'>
<input id="update_details_button" type='submit' class='btn btn-primary wide' value='Change'/>
</div>
</form>
views.py
def user_view(request, is_admin):
user = request.user
form = myForm()
if request.method == 'POST' and is_admin:
form = myForm(request.POST)
if form.is_valid():
data = form.cleaned_data
user.name = data['name']
user.country = data['country']
user.save()
messages.success(request, 'You have successfully updated your details.')
return render(request, 'mysite/user.html', {
'user': user,
'is_admin': is_admin,
'form': form,
})
My form is as followed
class myForm(forms.Form):
name = forms.CharField(
label="Name",
widget=forms.TextInput(attrs={'placeholder': 'Name'}))
country = CountryField(blank_label='(select country)')
def __init__(self, *args, **kwargs):
super(myForm, self).__init__(*args, **kwargs)
The name field displayed fine on the page but there's no sign of the CountryField, could someone point out the error? The code compiled fine and gives no error while server is running.
CountryField is a model field, not a form field. You're supposed to add it to your user model, in which case a modelform based on that model will automatically generate a country field. Since it looks like you have actually added a field called country to the User model, that's where you should be using CountryField.
However, for reference, to do it manually on a non-model form is slightly more complicated:
from django_countries import widgets, countries
class myForm(forms.Form):
country = forms.ChoiceField(widget=CountrySelectWidget, choices=countries)
In fact it's simpler: https://pypi.org/project/django-countries/#custom-forms
from django_countries.fields import CountryField
class MyForm(forms.Form):
country = CountryField(blank=True).formfield()
If you have installed django_country and it added in installed app than no need to make it from just use like this
{% load countries %}
<select name="country">
{% countries %}
<option value="{{ code }}">{{ name }}</option>
{% endcountries %}
</select>

Django: Creating a form per user on one page

Sorry the title isn't very descriptive. The context: I have an event full of participants. When the event is over I want to leave feedback for all of the other participants.
models.py
class Feedback(models.Model):
action = models.ForeignKey(Action)
feedback_by = models.ForeignKey(UserProfile, related_name='feedback_by')
feedback_for = models.ForeignKey(UserProfile, related_name='feedback_for')
comment = models.CharField(max_length=200)
no_show = models.BooleanField()
created = models.DateTimeField()
modified = models.DateTimeField()
forms.py
class FeedbackFormSet(BaseModelFormSet):
def add_fields(self, form, index):
super(FeedbackFormSet, self).add_fields(form, index)
form.fields['is_checked'] = forms.BooleanField(required=False)
class FeedbackForm(forms.ModelForm):
comment = forms.CharField(label=(u"Comment"), widget=forms.Textarea())
class Meta:
model = Feedback
fields = ['comment', 'no_show']
I want to create a feedback page, where there would be one instance of the FeedbackForm for each participant. After some searching it seems that to do that I want to be using a FormSet, but I'm not finding the documentation for it very helpful and I can't seem to find any good examples.
If a formset is the way to go, could you guys help me out with some (view/formset basically) starter code? If not, can you point me to what I should be doing? Thanks.
EDIT: I've added my view and template code below.
views.py
#login_required
def new_feedback(request, action_id):
action = get_object_or_404(Action, id=action_id)
profile = UserProfile.objects.get(user_id=request.user.id)
participants = all_info_many_profiles(action.participants.filter(~Q(id=profile.id)))
fbformset = modelformset_factory(Feedback, form=FeedbackForm, formset=FeedbackFormSet)
if request.method == 'POST':
formset = fbformset(request.POST, request.FILES, queryset=action.participants.filter(~Q(id=profile.id)))
if formset.is_valid():
formset.save()
else:
print formset.errors
else:
formset = fbformset(queryset=action.participants.filter(~Q(id=profile.id)))
return render(request, 'app/new_feedback.html',
{'action': action, 'participants': participants, 'formset': formset}
new_feedback.html
{% block body_block %}
<h1>Leave Feedback</h1>
{% for participant in participants %}
<li>{{ participant.username }}</li>
{% endfor %}
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }} <br />
{% endfor %}
<input type="submit" name="submit" value="Submit Feedback" />
</form>
{% endblock %}
What I'm trying to achieve is to associate one form to each user in the list (or queryset) of participants. What I currently have shows one more form than I want (for example, when I list each user I'll see 3 names but 4 forms example) and I don't know if or how the users/forms are related.
The idea is that the feedback_for field will get its value automatically, ie in the view I would do:
if formset.is_valid():
for form in formset:
a = form.save(commit=false)
a.feedback = participant
a.save()
On top of that, I added an extra field "is_checked" which is intended to specify whether I'm leaving feedback for that user or not. Example of full functionality:
user1 [X] is_checked
... rest of form
user2 [] is_checked
... rest of form
user3 [X] is_checked
... rest of form
Then when I hit submit it will create two new entries in the Feedback table, one for user1 and one for user3

Django forms - form field for each model

I am stuck with a problem - I want to add a simple form field to edit the objects that I am looping through in the template. Here's my model:
class Topic(BaseModel):
name = models.TextField()
Here's my model form:
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ["name"]
And here's my views:
def App(request):
tname = Topic.objects.get(pk=1)
if request.method == "POST":
form = TopicForm(data = request.POST, instance=tname)
if form.is_valid():
form.save()
And my template is simple:
{% for lecture in lectures %}
<form action="/app/" method="POST">
{% csrf_token %}
{{ form }}
<input type="submit" value="Post">
</form>
{% endfor %}
The thing is that I want to have a form field to edit EACH model not just one that has a pk of 1... how do I do that ?
I think you need to do objects.all() instead of get(pk=1). Then loop over those objects, and save them to a list that you save to the context. Something like this:
tnames = Topic.objects.all()
lectures = []
for tname in tnames:
lectures.append(TopicForm(instance=tname))
context = {
'lectures' : lectures
}
More specifically, you probably want to look into Model formsets. See https://docs.djangoproject.com/en/1.6/topics/forms/modelforms/#changing-the-queryset. Then you can directly give a queryset as initial data.

Categories