I'm making an election information app, and I want to allow the currently logged-in user to be able to declare himself and only himself as a candidate in an election.
I'm using Django's built-in ModelForm and CreateView. My problem is that the Run for Office form (in other words, the 'create candidate' form) allows the user to select any user in the database to make a candidate.
I want the user field in the Run for Office to be automatically set to the currently logged-in user, and for this value to be hidden, so the logged-in user cannot change the value of the field to someone else.
views.py
class CandidateCreateView(CreateView): model = Candidate form_class = CandidateForm template_name = 'candidate_create.html' def form_valid(self, form): f = form.save(commit=False) f.save() return super(CandidateCreateView, self).form_valid(form)
forms.py
class CandidateForm(forms.ModelForm): class Meta: model = Candidate
models.py
class Candidate(models.Model): user = models.ForeignKey(UserProfile) office = models.ForeignKey(Office) election = models.ForeignKey(Election) description = models.TextField() def __unicode__(self): return unicode(self.user) def get_absolute_url(self): return reverse('candidate_detail', kwargs={'pk': str(self.id)})
Remove user field from rendered form (using exclude
or fields
, https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#selecting-the-fields-to-use )
class CandidateForm(forms.ModelForm): class Meta: model = Candidate exclude = ["user"]
Find user profile and set user field in the create view.
class CandidateCreateView(CreateView): ... def form_valid(self, form): candidate = form.save(commit=False) candidate.user = UserProfile.objects.get(user=self.request.user) # use your own profile here candidate.save() return HttpResponseRedirect(self.get_success_url())
We don't want to set null=True
becaues we don't want to allow null
users at the model and/or database level
We don't want to set blank=True
to mess with the readability of model because the user actually will not be blank
@nbm.ten solution is a good one. It has an advantages over other 'solutions'to this problem that utilized model to set the user (like this one) in nbm.ten's doesn't undermine the assumptions above. We don't want to mess with the model to fix a problem in view!
But here I add two other solutions based on django documentation (Models and request.user):
from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic.edit import CreateView from myapp.models import Candidate class CandidateCreate(LoginRequiredMixin, CreateView): model = Candidate exclude = ['user'] def form_valid(self, form): form.instance.user = self.request.user return super().form_valid(form)
class CandidateForm(ModelForm): class Meta: model = Candidate exclude = [ 'user',] class CandidateAddView(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): form = CandidateForm() context = {'form':form} return render(request, 'myapp/addcandidateview.html', context) def post(self, request, *args, **kwargs): form = CandidateForm(request.POST) form.instance.user = request.user if form.is_valid(): form.save() return redirect(reverse('myapp:index'))
Note that LoginRequiredMixin
prevents users who aren’t logged in from accessing the form. If we omit that, we'll need to handle unauthorized users in form_valid()
or post()
.
Also exclude = ['user']
prevents the user field to be shown on the form.
We used form.instance.user
to set the user not form.data
or form.cleaned_data
they don't work
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With