I have a model form with custom constructor. It checks if a file is required and if false, it deletes the file field. It also has two hidden fields, which I initialize at my views. The form class is as follows:
class SubmitTask(forms.ModelForm):
task = forms.ModelChoiceField(queryset=Task.objects.all(), widget=forms.HiddenInput())
student = forms.ModelChoiceField(queryset=UserProfile.objects.all(), widget=forms.HiddenInput())
def __init__(self, file_required=False, *args, **kwargs):
super(SubmitTask, self).__init__(*args, **kwargs)
if file_required is True:
file = forms.FileField(
label='Select a file',
help_text='max: 2.5 MB'
)
else:
del self.fields['file']
class Meta:
model = Submission
exclude = ('date_submitted',)
My problem is that the hidden fields are populated when I initialize the form (I have confirmed that its values are indeed initialized by viewing the HTML code). However, the values of the hidden fields are not populated during POST request. I have confirmed during POST request that the form is indeed bound and I also confirmed on Firebug that POST also contains the task and student values. This is the involved method in my views.py
def view_task(request, id):
task = Task.objects.get(pk=id)
profile = request.user.get_profile()
data = {}
data['classroom'] = task.get_classroom()
data['description'] = task.get_description()
teacher_classrooms = Classroom.objects.filter(teacher=profile)
teacher_tasks = Task.objects.filter(classroom__in=teacher_classrooms)
if not submission and task not in teacher_tasks:
form = SubmitTask(file_required=task.file_required, initial={'task':task.pk, 'student':profile.pk})
data['form'] = form
if request.method == 'POST':
form = SubmitTask(request.POST, request.FILES)
if form.is_valid():
form.save()
return render_to_response('classrooms/view_task.html',
data, context_instance=RequestContext(request))
Your view function looks incorrect to me:
Where does the submission variable come from, when initializing the posted form you are missing the file_required parameter and the form processing should perhaps be reorganized to something like:
if request.method == 'POST':
form = SubmitTask(task.file_required, request.POST, request.FILES)
...
else:
form = SubmitTask(task.file_required, ...)
data['form'] = form
Related
So, How can I update some Model Fields automatic, without the user having to input the values?
In Models:
class Url(models.Model):
long_url = models.CharField("Long Url",max_length=600)
short_url = models.CharField("Short Url",max_length=7)
visits = models.IntegerField("Site Visits",null=True)
creator = models.ForeignKey(CurtItUser,on_delete=models.CASCADE,null=True)
def __str__(self):
return self.short_url
In Views:
def home(request):
"""Main Page, Random Code Gen, Appendage Of New Data To The DB"""
global res,final_url
if request.method == 'POST':
form = UrlForm(request.POST)
if form.is_valid():
res = "".join(random.choices(string.ascii_uppercase,k=7))
final_url = f"127.0.0.1:8000/link/{res}"
form.save()
redirect(...)
else:
form = UrlForm
return render(...)
Sow how can for exapmle set from my view the value of short_url to final_url ???
You can get the data you need from the form.
you need to get the specific instance first, then you can use that instance to save values from the form.
And do not forget to save!
url_instance = get_object_or_404(Url, pk=pk)
url_instance.short_url = form.cleaned_data['short_url']
url_instance.long_url = form.cleaned_data['long_url']
url_instance.visits = form.cleaned_data['visits']
url_instance.save()
You can find more detailed infromations in the Django Documentation.
I'm new to Django and I have built a Form that shows a single select field to chose from. The data in the field are calculated on the go by the Form.
I now need, once the data is being submitted, to be save on the database. The only problem is that, for some reason, I got an IntegrityError error NOT NULL constraint failed: manager_playlist.user_id
Below my view, form and model in Django
views.py
def playlist(request):
if not is_user_already_auth_spotify(request):
messages.error(request, "You're not authenticated with Spotify, please authenticate here")
return redirect('/members/account/' + request.user.username)
if request.method == "POST":
form = ChoosePlaylistForm(request.POST, request=request)
if form.is_valid():
form.save()
messages.success(request, "Playlist successfully chosen")
return HttpResponseRedirect('account')
else:
pass
else:
form = ChoosePlaylistForm(request=request)
return render(request, 'show_playlist.html', {"playlist_choose_form": form})
forms.py
class ChoosePlaylistForm(ModelForm):
playlists = forms.ChoiceField(choices=())
class Meta:
model = Playlist
fields = ('playlists',)
def __init__(self, *args, request=None, **kwargs):
super(ChoosePlaylistForm, self).__init__(*args, **kwargs)
self.request = request
self.fields['playlists'].choices = self.generate_selection()
def generate_selection(self):
sp_auth, cache_handler = spotify_oauth2(self.request)
spotify = spotipy.Spotify(oauth_manager=sp_auth)
s_user = spotify.current_user()
u_playlists = spotify.user_playlists(s_user['id'], limit=10)
choices = []
for playlist in u_playlists["items"]:
if playlist["owner"]["id"] == s_user['id']:
playlist_choice = (playlist["id"], playlist["name"])
choices.append(playlist_choice)
else:
pass
return choices
model.py
class Playlist(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
playlists = models.CharField(max_length=50, null=True, blank=True) # playlists are the ids of the playlists
def __str__(self):
return self.playlists
The reason for the error is that when a new Playlist object is created, the user field must not be empty (you did not add null=True, and of course, would not make sense here if you did). Now the form validates because the form does not require the user field, only the playlists field. You have a couple of choices.
Option 1
Add the required field to your form (I haven't tested this, please check the docs!):
class ChoosePlaylistForm(ModelForm):
playlists = forms.ChoiceField(choices=())
class Meta:
model = Playlist
fields = ('playlists', 'user',) # NOTE THE CHANGE HERE
def __init__(self, *args, request=None, **kwargs):
super(ChoosePlaylistForm, self).__init__(*args, **kwargs)
self.request = request
self.user = request.user # Add the user to the form
Option 2
Save the form as is using commit=False, then add the missing field before you save your model:
if request.method == "POST":
form = ChoosePlaylistForm(request.POST, request=request)
if form.is_valid():
playlist = form.save(commit=False) # NOTE THE CHANGE HERE
playlist.user = request.user # Add the user to the partial playlist
playlist.save() # Now you can save the playlist
messages.success(request, "Playlist successfully chosen")
return HttpResponseRedirect('account')
Option 3
Add the field when you instantiate the form itself (I'm not sure my syntax is correct here):
form = ChoosePlaylistForm(request.POST, request=request, instance=request.user)
EDIT
Option 3 above does not seem to work. I believe this edit will:
form = ChoosePlaylistForm(request.POST, request=request, initial={'user': request.user})
I am trying to create a form that allows current logged in user to submit data.
The form comprises of the field - amount, rate(interest), timestamp(automatically picked up), and currently logged in user.
Data is not passing into the database and giving an error like - The view investors.views.InvestView didn't return an HttpResponse object. It returned None instead.
views.py
def InvestView(request):
if request.method == 'GET':
investment_form = InvestorsForm(request.user)
context = {'investment_form': investment_form}
return render(request, 'investors/form.html', context)
if request.method == 'POST':
investment_form = InvestorsForm(request.POST or None, instance=request.user)
if investment_form.is_valid():
amount = investment_form.cleaned_data['amount']
interest = investment_form.cleaned_data['rate']
saving = investment_form.save(commit=False)
# Passing Logged in user
investor = request.user
print(investor)
saving.investor = request.user.id
saving.save()
messages.success(request, f'New Investment Done!')
return redirect('/myinvest/')
forms.py
class InvestorsForm(forms.ModelForm):
class Meta :
model = Investment
fields = ['amount', 'rate']
def __init__(self, user, *args, **kwargs):
self.user = user
super(InvestorsForm, self).__init__(*args, **kwargs)
models.py
class Investor(models.Model):
name = models.CharField(max_length=99)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Investment(models.Model):
amount = models.FloatField(blank=False)
rate = models.FloatField(blank=False)
timestamp = models.DateField(default=datetime.now)
investor = models.ForeignKey(Investor, on_delete=models.CASCADE)
def __str__(self):
return str(self.investor)
Data must be stored into the database and redirect the page to myinvest section simultaneously.
This issue has nothing to do with adding the user. It is because you do nothing in case the validation fails.
You should turn your function the other way round so that the render is hit in all cases.
def InvestView(request):
if request.method == 'POST':
investment_form = InvestorsForm(request.POST)
if investment_form.is_valid():
saving = investment_form.save(commit=False)
saving.investor.user = request.user
saving.save()
messages.success(request, f'New Investment Done!')
return redirect('/myinvest/')
else:
investment_form = InvestorsForm()
context = {'investment_form': investment_form}
return render(request, 'investors/form.html', context)
Note the indentation.
The actual failure to validate is because you have changed the signature of the form to accept a user parameter first, instead of the expected data. However it is not clear why you have done this as you do not use that value, but instead set the user in the view. You should remove that __init__ method.
Another error: your form's __init__ method takes a user as its first argument:
def __init__(self, user, *args, **kwargs):
In the case of a GET request, you pass it correctly:
investment_form = InvestorsForm(request.user)
But then with a POST request, you forget it:
investment_form = InvestorsForm(request.POST or None, instance=request.user)
Passing request.user as the first argument there as well should help.
You need to replace saving.investor = request.user.id with saving.investor.user = request.user.
I am using django to digitalise a form. This form is a little bit complex, and there are a lot of fields in it. I was wondering if Django could do form.cleaned_data[] for all fields, in stead of declaring variables like obj.fieldname = form.cleaned_data['fieldname'] for each field apart.
I tried it with a forloop in the views.py, but that won't work
This is the forloop I'm talking about:
def get_form_naw(request):
if request.method == 'POST':
form = Form1(request.POST)
if form.is_valid():
for x in Model1():
formname = x.name
o = Model1()
o.formname = form.cleaned_data[formname]
o.save()
else:
form = Form1
return render(request, 'folder/home.html', context=locals())
I'm using a mysql database. My forms are declared like this:
forms.py
class Form1(forms.ModelForm):
class Meta:
model = Model1
exclude = ('id')
You shouldn't have to loop through the fields. You are using a model form, so you should just save the form:
if form.is_valid():
obj = form.save()
...
If you really need to set fields dynamically, you can use setattr.
fieldname = 'username'
value = 'my_user'
setattr(obj, fieldname, value)
you can get the instance of the data before saving like this:
if form.is_valid():
obj = form.save(commit=False) #get instance without saving
# do your thing
obj.save() #save into database
I want to keep the form fields preserved after submitting the form. I can preserve all the fields except the checked checkboxes
Here is my form action view:
def student_submit_info(request):
form_values = {}
if request.method == 'POST':
form = StudentForm(request.POST)
print form.is_valid()
form_values = getDetails(request)
if form.is_valid():
print request.user.username
student = Student.objects.get(user=request.user)
// saving student to DB
saveDetails(request, student, form_values)
return render_to_response('student.html', form_values, context_instance=RequestContext(request))
def getDetails(request):
#fetch input data
form_values = {}
form_values['first_name'] = request.POST['first_name']
form_values['last_name'] = request.POST['last_name']
form_values['skills'] = request.POST.getlist('skills[]')
return form_values
I would want to preserve skills (checkbox), here's a part of my template
skill1<input type="checkbox" name="skills[]" checked value="skill1"/>
skill2<input type="checkbox" name="skills[]" value="skill2"/>
skill3<input type="checkbox" name="skills[]" value="skill3"/>
You should make a custom django Forms to handle easily forms, example of a post view:
def post_view(request):
form = MyForm(request.POST)
if form.is_valid():
do_something()
render(request, 'your_temp', {'MyForm': MyForm'})
With this kind of snippet, data in form will always be those sent.
You can override is_valid() for empty skill checkboxes.
Perhaps, use CBV's and ModelForms to make the process simpler.
Combine a listview (or similar) and add your form via context.
Then in get_context_data of your CBV:
form_values = {}
#Simpler code below for accessing post dictionary
for key, value in self.request.POST.items():
if value == 'on':
form_values[key] = value
context = super().get_context_data(**kwargs)
# You need to add form_values to make it accessible in the forms.py
context['form'] = YourFormName(form_values)
Then, in your forms.py (I'm hoping you use modelforms):
def __init__(self, filters, *args, **kwargs):
super(YourFormName, self).__init__(*args, **kwargs)
if len(form_values) > 0:
for field_name in self.fields:
if field_name in filters:
self.fields[field_name].widget = forms.CheckboxInput(attrs={'checked': True})
I hope this helps.