request not defined inside forms.py class (forms.Form) - django

The error
NameError: name 'request' is not defined
My forms.py
class PersonForm(forms.Form):
name = forms.CharField(required=False)
job_title = forms.CharField(required=False)
status = forms.TypedChoiceField(choices=Person.STATUS_CHOICES)
project = Project.objects.get(users=request.user, pk=self.kwargs.get('pk'))
company = forms.ModelChoiceField(queryset=project.companies.all(),required=False)
new_company = forms.CharField(required=False)
note = forms.CharField(required=False)
def __init__(self, *args, **kwargs):
super(PersonForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
def clean(self):
return self.cleaned_data
views.py
class PersonCreate(LoginRequiredMixin, FormView):
template_name = 'person/person_form.html'
form_class = PersonForm
success_url = '/project/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
cleaned_data = form.clean()
active_project = self.request.session['active_project']
project = Project.objects.get(users=self.request.user, pk=self.request.session['active_project'])
if cleaned_data['name']:
person, created = Person.objects.get_or_create(
name=cleaned_data['name'],
job_title=cleaned_data['job_title'],
created_by=self.request.user,
status=cleaned_data['status'],
project=project
)
if cleaned_data['new_company']:
company, created = Company.objects.get_or_create(name=cleaned_data['new_company'], project=project, created_by=self.request.user)
company.persons.add(person)
company.save()
if cleaned_data['note']:
person.note_set.create(content=cleaned_data['note'], created_by=self.request.user)
person.save()
if cleaned_data['company']:
company = project.companies.get(name=cleaned_data['company'])
company.persons.add(person)
company.save()
return super().form_valid(form)
def get_success_url(self):
return self.request.POST.get('next', '/project/' + str(self.request.session['active_project']))
I want to filter the queryset on the forms.ModelChoiceField field company. Based on the companies of the project the user has access to. How would I do that? Can I access request.session data as well here?

You can't do that like this, because Django forms don't have access to the request at all.
So the best approach I can think of is to pass the user to the form and then use the data when initialized.
First you have to pass the user and pk in the view.
views.py:
# ...
form = PersonForm(user=request.user, pk=kwargs.get('pk'))
Then in your form, you can catch both kwargs and update the project with the correct value,
class PersonForm(forms.Form):
# your form fields code ...
def __init__(self, *args, **kwargs):
# get the user and pk
user = kwargs.pop('user', None)
pk = kwargs.pop('pk', None)
# update project field
super(PersonForm, self).__init__(*args, **kwargs)
self.fields['project'] = Project.objects.get(users=user, pk=pk)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'

In class-based views to update Form kwargs:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({"request": self.request})
return kwargs

Related

Django FormView: Add if record does not exist and update if it does exist

I created a FormView and it works fine if the user executed the process the first time. However when it is executed the second time I get an error that the record already exist. This is expected as the user in the model is unique. How can I overcome this problem so that the current record is overwritten by the form.save if the record already exist.
models.py
class ttemp_selection(models.Model):
select_account = models.ForeignKey(tledger_account, on_delete=models.CASCADE)
date_from = models.DateField(default=datetime.today)
date_to = models.DateField(default=datetime.today)
user = models.ForeignKey(custom_user, on_delete=models.CASCADE, unique=True)
def __str__(self):
return self.select_account
forms.py
class Meta:
model = ttemp_selection
fields = ['select_account', 'date_from', 'date_to', 'user']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(SelectAccountForm, self).__init__(*args, **kwargs)
user = self.request.user
current_company = user.current_company
self.fields['select_account'].queryset = tledger_account.objects.filter(
company=current_company, gl_category='Cash and Bank')
view.py
class sasView(FormView):
template_name = 'cashflow/select_account.html'
form_class = SelectAccountForm
success_url = 'home'
def form_valid(self, form):
form.save()
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super(sasView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
I can determine the record by using ttemp_selection.objects.get(user=request.user)
I know I can make use of the UpdateView class but that will create a problem when the record does not exist. It will also add an extra step that is unnecessary.
Assistance will be appreciated.
You can work with a CreateView, and slightly alter the behavior to specify a self.object if that exists:
from django.contrib.auth.mixins import LoginRequiredMixin
class sasView(LoginRequiredMixin, CreateView):
template_name = 'cashflow/select_account.html'
form_class = SelectAccountForm
success_url = 'home'
def get_form(self, *args, **kwargs):
self.object = ttemp_selection.objects.filter(
user=self.request.user
).first()
return super().get_form(*args, **kwargs)
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super(sasView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
It however makes no sense to include the user as field, since - if I understand it correctly - you use the logged in user. By including it, you make it possible that a person forges a POST request, and thus changes the account of a different user. You should omit this filed:
class SelectAccountForm(forms.ModelForm):
class Meta:
model = ttemp_selection
# no user ↓
fields = ['select_account', 'date_from', 'date_to']
# …
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin mixin [Django-doc].

How do I filter values in Django CreateView, UpdateView

I am trying to use CreateView and UpdateView to modify records. My problem is that the ForeignKey dropdown lists values (Psa.number) for all companies instead only those of the company to which the user belongs.
class Psa(models.Model):
owner = models.ForeignKey(Employer)
number = models.PositiveIntegerField(unique=True...
type = models.CharField(max_length=6 ...
class Employer(models.Model):
employer_name = models.CharField(max_length=100, unique=True)
The form:
class PsaCreateForm(forms.ModelForm):
class Meta:
model = Psa
fields = [
'number',
'type',
]
What is the best way to solve this? I've got several other conditions that use the same company foreignkey relationship so is there a way to create a method on the model that I can reuse?
You need get_form_kwargs(self) in CreateView and UpdateView:
forms.py:
class PsaCreateForm(forms.ModelForm):
model = Psa
fields = [
'number',
'type',
]
def __init__(self, *args, **kwargs):
self.current_user = kwargs.pop('user')
super(PsaCreateForm, self).__init__(*args, **kwargs)
if self.current_user:
self.fields['number'].queryset = Psa.objects.filter(owner=self.current_user)
views.py
class PsaCreate(CreateView):
model = Psa
template_name = 'form.html'
form_class = PsaCreateFrom
def get_form_kwargs(self):
kwargs = super(PsaCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
Also a good idea. Set def dispatch(self, request, *args, **kwargs): in your Views.
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.owner != self.request.user:
return HttpResponseRedirect(reverse('home'))
return super(PsaUpdate, self).dispatch(request, *args, **kwargs)

how to access/modify django model fields before validating its form in Listview

I have a model Course that has the following attr:
class Course(models.Model):
user= models.ForeignKey(
User,
on_delete=models.CASCADE,
)
# email= models.EmailField(default=user.email)
courseName= models.CharField(max_length=20, blank=False)
class Meta:
unique_together= ('user','courseName',)
def __str__(self):
return self.courseName
I have created a form where I want the user to enter just the courseName and after they POST it, I will add the requested user in the model as well.
This is my form which is getting passed on to the template via my ListView
forms.py
class CourseForm(forms.ModelForm):
class Meta:
model= Course
fields = ['courseName']
**Here is my views.py where I am struggling with **
class CoursesListView(ListView, FormMixin):
model = Course
form_class = CourseForm
template_name = "userApp/courseList.html"
def get_queryset(self):
return Course.objects.filter(user__exact=self.request.user)
def get_context_data(self,*args,**kwargs):
context= super(CoursesListView,self).get_context_data(*args, **kwargs)
context['courseForm'] = self.form_class
return context
def post(self,request, *args, **kwargs):
form = self.form_class(request.POST)
user = User.objects.get(username__exact=self.request.user)
**I want to add the user to my model.user field here**
return self.get(redirect, *args, **kwargs)
def get(self,request, *args, **kwargs):
self.object=None
self.form = self.get_form(self.form_class)
return ListView.get(self, request, *args, **kwargs)
So basically my question is how can I add the user in my model before calling form.is_valid().
something like this?
def post(self,request, *args, **kwargs):
form_data = copy.copy(request.POST)
form_data['user'] = User.objects.get(username__exact=self.request.user).pk
form = self.form_class(form_data)
# form handling follows
return self.get(redirect, *args, **kwargs)
This Answer was suggested by a user who deleted this answer. Didnt get his user id but whoever you were thanks a lot for the help!!!
Just use form.save(commit=False) and then make the necessary changes.
def post(self,request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
user = User.objects.get(username__exact=self.request.user)
instance = form.save(commit=False)
instance.user = user
instance.save()

NOT NULL constraint failed when save ModelForm

I am new in Django (1.9)
I have a NOT NULL constraint failed when I save my ModelForm and i don't understand why ...
I propose to the user a form to post a comment and the only field include in the form is "text", i want to set the excluded fields in my view after the validation and before save in database
Models.py :
class Commentaire(models.Model):
text = RichTextField()
pub_date = models.DateTimeField()
author = models.ForeignKey(User)
post = models.ForeignKey(Post)
publish = models.BooleanField()
def __str__(self):
return "/%s/%s" % (self.pub_date,self.author.username)
class Meta:
ordering = ["-pub_date"]
Forms.py :
class CommentaireForm(forms.ModelForm):
class Meta:
model = Commentaire
fields = ['text']
Views.py :
class PostDetail(View):
def get(self, request, *args, **kwargs):
view = PostDisplay.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = PostComment.as_view()
return view(request, *args, **kwargs)
class PostDisplay(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDisplay, self).get_context_data(**kwargs)
context['form'] = CommentaireForm()
return context
class PostComment(SingleObjectMixin, FormView):
template_name = 'blogengine/post_detail.html'
form_class = CommentaireForm
model = Post
def post(self, request, *args, **kwargs):
#if not request.user.is_authenticated():
# return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""
If the form is valid, redirect to the supplied URL
"""
form.save(commit=False)
form.post = self.object
form.author = self.request.user
form.pub_date = datetime.now()
form.publish = True
form.save()
return HttpResponseRedirect(self.get_success_url())
When Django save the form, i have this exception :
NOT NULL constraint failed: blogengine_commentaire.pub_date
The values i set for the excluded fields (author, post, pub_date) in "form_valid" are not taken into account, they seem to stay NULL
Could you explain me why because i am lost ?
Thanks
You need to rewrite form_valid method like that
def form_valid(self, form):
"""
If the form is valid, redirect to the supplied URL
"""
model_instance = form.save(commit=False)
model_instance.post = self.object
model_instance.author = self.request.user
model_instance.pub_date = datetime.now()
model_instance.publish = True
model_instance.save()
return HttpResponseRedirect(self.get_success_url())
Because save(commit=False) will return you an Post instance that you then need to populate and save.

User current user on new Django class views forms

I am using the django 1.3 on trunk, and start learning about class views.
I had this:
class Project(models.Model):
title = models.CharField(max_length=90)
slug = models.CharField(max_length=90)
description = models.TextField()
owner = models.ForeignKey(User)
class ProjectForm(ModelForm):
class Meta:
model = Project
exclude = ('owner',)
widgets = {
'description': Textarea(attrs={'cols': 40, 'rows': 20}),
}
class ProjectCreateView(CreateView):
model = Project
form_class = ProjectForm
def get(self, request, *args, **kwargs):
return super(ProjectCreateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return super(ProjectCreateView, self).post(request, *args, **kwargs)
I am trying, to get a form using model forms from django excluding the owner field, to get the field value after with the request.user property.
The form as it is, works. But how can make sure the ModelForm use request.user for the Project.owner field?
My first guess, was to override get_form_kwargs method from the view
class ProjectCreateView(CreateView):
# .....
def get_form_kwargs(self, **kwargs):
self.initial['owner': self.request.user})
kwargs = super(ProjectCreateView, self).get_form_kwargs(**kwargs)
return kwargs
But seem to have no effect on the data used by the model form
get_form_kwargs is supposed to return a dict of arguments for your form - you set self.initial, but you didn't attach it to kwargs:
def get_form_kwargs(self, **kwargs):
kwargs = super(ProjectCreateView, self).get_form_kwargs(**kwargs)
kwargs['initial']['owner'] = self.request.user
return kwargs