django - load currently logged in user information in the form - python

django noob here.
The question i am going to ask has been asked several times, however, i couldn't find the answers which can help my case.
the query is:
I have a Form having a choice field which loads its choices information from the database. Basically, I have designed my models in such a way that, the choices displayed is individual to the users.
for example:
for user1, the choice field shows a,b,c,d.
where as for user 2, the choice field shows v,w,d.
The problem i am facing is referencing the logged in user and getting the username. then pass the username as the filter to the database.
I have come across numerous init functions trying to do this, somehow it is not helping my case.
forms.py
class class_model(forms.Form):
class_name = forms.ChoiceField(
required=False,
widget=forms.Select,
)
def __init__(self, user, *args, **kwargs):
self.user = user
super (class_model, self).__init__(*args, **kwargs)
current_user = self.user
name = current_user.username
k = User.objects.get(username=name)
y = UserProfile.objects.get(user=k)
schoolid = y.schoolid
primary_filter = Class1.objects.filter (school_id=schoolid)
ax = [("Choose Class", "Choose Class")] + list (primary_filter.objects.values_list ('class_name', 'class_name').distinct())
self.fields['class_name'].choices = ax
The error i receive: 'QueryDict' object has no attribute 'username'
Update:
views.py
#login_required(login_url="login/")
def create(request):
print(request.method)
if request.method == 'POST':
form2 = class_model(request.POST, request.user)
if form2.is_valid():
class_name = form2.cleaned_data['class_name']
return render(request, 'create_student.html', {'form2': form2}
else:
print(form.errors)
return render(request, 'create_student.html', {'form2': form2})

You've told the form to expect the user as the first positional parameter, so you need to pass it there.
form2 = class_model(request.user, data=request.POST)

Related

Save data from ChoiceField to database Django

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})

How can I pass current logged in user while form submission in django?

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.

Django Forms:Post request is got but data is not saved

So I'm trying to build a Django site that collects Mod Applications to learn Django Forms. Except that I'm an idiot and I don't know what am I doing.
The thing that I'm trying to do is collect and save the Form data the current part and later try to show that data in the Django Admin the part I still haven't done and don't know how.
When I fill out the form I get [06/May/2017 19:38:29] "POST /modapp HTTP/1.1" 200 2354
This is my forms.py:
class Application(forms.ModelForm):
class Meta:
model = ModApplication
fields = ('discord', 'reddit', 'serverrank','finds','serverstay','active','timezone','reason','helped','help')
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
self.fields['discord'].widget.attrs['placeholder'] = 'UnknownDeveloper#2068'
self.fields['reddit'].widget.attrs['placeholder'] = '/u/UnknownDeveloper'
self.fields['serverrank'].widget.attrs['placeholder'] = 'GEOCACHING + RANK'
self.fields['serverstay'].label = "How long have you been on the server"
self.fields['active'].label = "How active have you been on the server"
self.fields['timezone'].widget.attrs['placeholder'] = 'CET'
self.fields['reason'].label = "Why do you want to become a mod?"
self.fields['helped'].label = "How have you helped the server so far?"
self.fields['help'].label = "How will you help the server if you'll become a mod"
models.py
class ModApplication(models.Model):
def __unicode__(self):
return "Discord User: " + self.discord + " aka " + self.reddit
reddit = models.CharField("Reddit Username", max_length=30)
discord = models.CharField("Discord Username", max_length=30)
serverrank = models.CharField("Server Rank", max_length=60)
finds = models.CharField("Finds", max_length=12)
serverstay = models.CharField("Stayed on the server for",max_length=200)
active = models.CharField("Is Actice on Discord for", max_length=500)
timezone = models.CharField("Timezone", max_length=20)
reason = models.TextField("He likes to become a mod because", max_length=5000)
helped = models.TextField("He helped by", max_length=5000)
help = models.TextField("He'll help by", max_length=5000)
views.py
def formtofill(request):
form = Application()
return render(request, 'appmod.html', {'form': form,})
if request.method == "POST":
form = Application(request.POST)
print(request.POST)
if form.is_valid():
user = form.save()
user.discord = request.discord
user.reddit = request.reddit
user.serverrank = request.serverrank
user.finds = request.finds
user.serverstay = request.serverstay
user.active = request.active
user.timezone = request.timezone
user.reason = request.reason
user.helped = request.helped
user.help = request.help
user.save()
print(user)
messages.success(request, 'Your Mod Application has been successfully submitted!')
print(form)
return HttpResponse('Successful')
else:
form_class = Application
I searched a lot but I didn't find anything. I tried to print debug messages but they didn't print anything. I put the messages module but nothing happened. HTTPResponse just reloads back to the form. Help will be gladly accepted. Thanks for your time. If I am missing something please tell me and i'll edit my post
It's a suprise that this code runs at all, it should be producing attribute errors for these:
user.discord = request.discord
user.reddit = request.reddit
But the reason that it doesn't is because the execution path never reaches that point
def formtofill(request):
form = Application()
return render(request, 'appmod.html', {'form': form,})
Because of that return statement.
Your corrected code should look like
def formtofill(request):
form = Application()
if request.method == "POST":
form = Application(request.POST)
print(request.POST)
if form.is_valid():
user = form.save()
messages.success(request, 'Your Mod Application has been successfully submitted!')
return HttpResponseRedirect('/success_url')
else:
form_class = Application
return render(request, 'appmod.html', {'form': form,})
Dont save the form upfront. Save but put commit=false.
Also remove that return statement as in the answer above mine.
user = form.save(commit=False).
Then an instance is created, but its not written into the database. Now you can do the assignments.
user = form.save(commit=False).
#Now....
user.discord = request.POST['discord']
user.reddit = request.POST['reddit']
user.serverrank = request.POST['serverrank']
user.finds = request.POST['finds']
user.serverstay = request.POST['serverstay']
....................
user.save()
return HttpResponse('Successful')
Instead you were trying to access the data as an attribute of the request object itself. The form data are contained in request.POST, then you have to access it from there.
Also,
else:
form = Application()
You need to instantiate the form class.

Select a valid choice is not one of the available choices

I'm new to Django. What i'm trying to do is to show some JSON response value which i converted into tuples to show in the choicefield of my Django form.
This is how i'm creating the tuples
usernamelist = []
useremaillist = []
for userobject in userobjects:
username = userobject['somevalue']
email = userobject['somevalue']
useremaillist.append(email)
usernamelist.append(username)
user_tuple = zip(usernamelist,useremaillist)
This is my form
class UserSelectForm(forms.Form):
users = forms.ChoiceField(label="Select user")
Then in my views i'm trying to put all these names into drop down list
selectform = UserSelectForm()
selectform.fields['users'].choices = user_tuple
its successfully showing but when i try to submit my form i'm getting Select a valid choice is not one of the available choices error.
This is where i'm trying to get the drop down selected value from submitted form
if request.method == 'POST' and 'preview' in request.POST:
selectform = UserSelectForm(request.POST)
if selectform.is_valid():
user_email = selectform.cleaned_data['users']
print user_email
return HttpResponseRedirect('/')
If you really need to manually decide the choices then you should include them as a requirement for the initializer for the form
class UserSelectForm()
def __init__(self, choices, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['users'].choices = choices
Then call it with the choices
UserSelectForm(user_tuple, request.POST or None)

Preserve checked checkboxes after post in django

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.

Categories