I'm attempting to update a choice field depending on the user permissions. I have a boolean field which if False (default) the standard user gets to see. Otherwise if a user has the permission I want to display everything.
views.py
class ExportFormView(FormView):
template_name = 'export.html'
form_class = ExportForm
success_url = '/'
def get_form_kwargs(self):
kwargs = super(ExportFormView, self).get_form_kwargs()
kwargs.update({
'request' : self.request
})
return kwargs
forms.py
class ExportForm(forms.Form):
def __init__(self, request, *args, **kwargs):
self.request = request
super(ExportForm, self).__init__(*args, **kwargs)
choice_list = []
if request.user.has_perms('tracker.print_all'):
e = Muid.objects.values('batch_number').distinct()
else:
e = Muid.objects.values('batch_number').distinct().filter(printed=False)
for item in e:
choice = item['batch_number']
choice_list.append((choice, choice))
batch_number = forms.ChoiceField(choices = choice_list)
Error I get:
NameError at /
name 'request' is not defined
Any help would be greatly appreciated, I've been stuck on this for a while now (And tried many googled SO suggestions/Answers.)
Found out how to do it, still interested in other ways.
Using pdb, I found that the view was setup correctly. But I had to alter the form. I couldn't access the variable from outside of a function such as __init__, others functions should be able to access the variable too, but I needed to create the form on init, so I couldn't wait for function calls.
Code:
Views.py
class ExportFormView(FormView):
template_name = 'export_muids.html'
form_class = ExportForm
success_url = '/'
def get_form_kwargs(self):
kwargs = super(ExportFormView, self).get_form_kwargs()
kwargs.update({
'request' : self.request
})
return kwargs
forms.py
class ExportForm(forms.Form):
def __init__(self, request, *args, **kwargs):
self.request = request
choice_list = []
if request.user.has_perms('tracker.print_all'):
e = Muid.objects.values('batch_number').distinct()
else:
e = Muid.objects.values('batch_number').distinct().filter(exported=False)
for item in e:
choice = item['batch_number']
choice_list.append((choice, choice))
super(ExportForm, self).__init__(*args, **kwargs)
self.fields['batch_number'] = forms.ChoiceField(choices = choice_list)
Related
How can I get data from a form (ProductCreateForm)?
If I write form = self.get_form(), then I just get a form template, where some data is selected, and some are not (select especially).
If I write form = ProductCreateForm(request.POST), then I get an error saying that the request was not found. Perhaps this is due to the fact that I set the request in get_context_data() and work with them in the __init__ method in the forms.py.
I process the data in the clean method in the forms.py.
I have the following view
class ProductsCreate(CreateView):
model = Product
form_class = ProductCreateForm
http_method_names = ['get', 'post']
def get_initial(self):
initial = super(ProductsCreate, self).get_initial()
initial['request'] = self.request
return initial
def get_context_data(self, *args, **kwargs):
ctx=super(ProductsCreate, self).get_context_data(*args, **kwargs)
ctx['special_form'] = SpeciallyPriceForm()
return ctx
def get(self, request, *args, **kwargs):
self.object = None
if kwargs.get('slug'):
category = Category.objects.filter(slug=kwargs.get('slug')).first()
self.initial.update({'category': category})
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
self.object = None
form = ProductCreateForm(request.POST) #What here?
special_form = SpeciallyPriceForm(self.request.POST)
if form.is_valid() and special_form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
forms
class ProductCreateForm(forms.ModelForm):
#....
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('initial').get('request')
super(ProductCreateForm, self).__init__(*args, **kwargs)
#...
user = self.request.user
provider = Provider.objects.filter(user=user.id).last()
self.fields['category'] = ModelMultipleChoiceField(queryset=provider.category.all())
#...
def clean(self):
cleaned_data = super(ProductCreateForm, self).clean()
cd_category = cleaned_data.get('category')
#...
class SpeciallyPriceForm(forms.ModelForm):
class Meta:
model = SpeciallyPrice
fields = ['adittional_specially_price', 'adittional_specially_number']
1.try pass request in that way
def get_initial(self):
"""
Returns the initial data to use for forms on this view.
"""
initial = super(ProductsCreate, self).get_initial()
initial['request'] = self.request
return initial
then in forms.py
def __init__(self):
kwargs.pop('initial').get('request')
Are you sure that is working at all? On init in your forms I don't see super() call so you should get an error?
Do you have problem only with category field the rest data you get properly?
Where do you pass it kwargs.pop('request') ??
You can print and check what is in self.request.POST
I have created two url paths.
path('addhours/<int:jobNr>/', views.AddHoursView.as_view(), name='addhours'),
path('addhours/', views.AddHoursView.as_view(), name='addhours'),
And a CreateView for these paths.
class AddHoursView(generic.CreateView):
template_name = "worktime/addhours.html"
form_class = AddHoursForm
success_url = reverse_lazy('worktime:myjobs')
def get_form_kwargs(self):
# pass "jobNr" keyword argument from the current url to form
kwargs = super(AddHoursView, self).get_form_kwargs()
kwargs['jobNr'] = self.kwargs.pop(JOB_PARAM, None)
return kwargs
And a form, where the number of fields depends on if the parameter exists in the URL.
class AddHoursForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
#Add jobworker field to from Worktime model if any jobNr pass in url
#When in url will be parameter. Job foreignkey will be set by automat.
self.jobNr = kwargs.pop('jobNr', None)
super(AddHoursForm, self).__init__(*args, **kwargs)
if not self.jobNr:
self.fields['jobWorker'] = forms.ModelChoiceField(queryset=Job.objects.all())
class Meta:
model = WorkTime
fields = ['date', 'hours', 'description']
widgets = {
'date': forms.SelectDateWidget(empty_label=("Choose Year",
"Choose Month",
"Choose Day"))
}
Now I want to have in AddHoursView context["jobNr"] = "bar" where the URL is /url/bar
In AddHoursView's def context_data(self, **kwargs) I tried:
self.request.GET gives me empty QueryDict
self.kwargs['jobNr'] give me a key error
I need access to the url parameter if it exist, to pass this jobNr to template, so override form_valid is not what I need.
At the moment you are popping the value from self.kwargs, which removes it. That means it is no longer there when you try to access it in get_context_data. Since the argument is optional, you can use get() instead.
Change the method to:
def get_form_kwargs(self):
kwargs = super(AddHoursView, self).get_form_kwargs()
kwargs['jobNr'] = self.kwargs.get('JOB_PARAM')
return kwargs
Then in get_context_data you can do:
def get_context_data(self, **kwargs):
kwargs = super(AddHoursView, self).get_context_data(**kwargs)
kwargs['jobNr'] = self.kwargs.get('JOB_PARAM')
return kwargs
I am having a valueerror on my redirect function below. I checked previous updates which specified that this would occur when the name argument is not specified. I already did but its still not working for some strange reason.
The traceback is below
ValueError at /
dictionary update sequence element #0 has length 0; 2 is required
views.py
class HomeView(TemplateView):
template_name = "home.html"
title = 'Your Dashboard'
def get_context_data(self, *args, **kwargs):
if self.request.user.is_authenticated():
fav_polls = PollFav.objects.filter(fav_user=self.request.user)
poll_types = []
for poll in fav_polls:
poll_types.append(poll.poll.polltype_id)
poll_types = Ptype.objects.filter(pk__in=list(set(poll_types)))
context = super(HomeView, self).get_context_data(*args, **kwargs)
context["submit_btn_value"] = "Send"
context["title"] = self.title
context["poll_types"] = poll_types
todate = datetime.datetime.now().date()
user = self.request.user
context["pollsCreated"] = Ptype.objects.filter(c_user=user).count()
context["pollsECreated"] = PollItem.objects.filter(user_submit=user).count()
try:
context["user"] = PUser.objects.get(user_id=self.request.user.id)
except:
#where the issue is
return redirect("PUserCreate")
return context
urls.py
url(r'^puser/add/$', PUserCreate.as_view(), name='PUserCreate'),
Thanks for the tips.
Instead of doing the redirect in get_context_data method, the redirect needs to be done from a get method(below).
"The method you have overriden is returning a value to the parent class' get method where it is trying to update the context dictionary with the value this method will return" - Sachin Kukreja
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
try:
print PUser.objects.get(user_id=self.request.user.id)
except:
return redirect('PUserCreate')
return self.render_to_response(context)
I do not want the logged in user to show up on this ModelMultipleChoiceField in order to restrict themselves from creating a following relationship with themselves? So how do I exclude the logged in user from the queryset, probably an easy fix but I'm new to Django and it has eluded me for a few hours now.
forms.py
class Add_Profile(forms.ModelForm):
def __init__(self,*args, **kwargs): # initializing your form in other words loading it
super(Add_Profile, self).__init__(*args, **kwargs)
user_id = kwargs.pop('user_id') # taking user_id out of the querylist
self.fields['follows'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=UserProfile.objects.filter(~Q(id=user_id)))
class Meta:
model = UserProfile
fields = (
'bio',
'follows',
'theme',
'profile_picture',
)
Views.py
#login_required
def edit_profile(request, user_id):
userprofile = UserProfile.objects.get(pk=user_id)
if request.method == 'POST':
edit_profile = Add_Profile(request.POST, request.FILES, instance=userprofile, user_id=request.user.id)
if edit_profile.is_valid():
edit_profile.save()
return redirect('/home/user/{0}/'.format(request.user.username))
else:
print edit_profile.errors
else:
edit_profile = Add_Profile(instance=userprofile, user_id=request.user.id)
return render (request, 'edit.html', {'form': edit_profile,})
Error: init() got an unexpected keyword argument 'user_id'
You can definitely do it using forms.Form instead of forms.ModelForm with something along the lines of this example in the docs:
from django import forms
from django.contrib.auth import get_user_model
class Add_Profile(forms.Form):
follows = forms.ModelMultipleChoiceField(queryset=None)
def __init__(self, user=None, *args, **kwargs):
super(Add_Profile, self).__init__(*args, **kwargs)
if user is not None:
self.fields['follows'].queryset = get_user_model().objects.exclude(pk=user.pk)
else:
self.fields['follows'].queryset = get_user_model.objects.all()
Just pass in the user you wish to exclude when you instantiate the form:
form = Add_Profile() # all users will be present in the dropdown
some_guy = User.objects.get(pk=4)
form = Add_Profile(user=some_guy) # all users except some_guy will be present
Define an __init__ method for the form class. Pass the logged in userid to the form while initializing it, this will work with a model form.
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id')
super(Add_Profile, self).__init__(*args, **kwargs)
self.fields['follows'] = forms.ModelMultipleChoiceField(queryset=UserProfile.objects.filter(~Q(user_id=user_id)))
While initializing your form, you can pass user_id
address_form = Add_Profile(request.POST, user_id=request.user.id)
I have a model along with a ModelForm based on that model. The ModelForm contains a ModelMultipleChoice field, which I specify in the subclass of my ModelForm:
class TransactionForm(ModelForm):
class Meta:
model = Transaction
def __init__(self, *args, **kwargs):
super(TransactionForm, self).__init__(*args, **kwargs)
self.fields['category'] = forms.ModelChoiceField(queryset=Category.objects.filter(user=user))
As you can see, I need to filter the Category queryset by user. In other words, users should only see their own categories on the drop down. But how can I do this when user, or more specifically, request.user, is not available in a Model instance?
Edit: Adding my subclass of the CBV:
class TransUpdateView(UpdateView):
form_class = TransactionForm
model = Transaction
template_name = 'trans_form.html'
success_url='/view_trans/'
def get_context_data(self, **kwargs):
context = super(TransUpdateView, self).get_context_data(**kwargs)
context['action'] = 'update'
return context
I tried form_class = TransactionForm(user=request.user) and I'm getting a NameError saying that request was not found.
You can pass request.user to form init in view:
def some_view(request):
form = TransactionForm(user=request.user)
and add user parameter to form __init__ method (or pop it from kwargs in form):
class TransactionForm(ModelForm):
class Meta:
model = Transaction
# def __init__(self, *args, **kwargs):
# user = kwargs.pop('user', User.objects.get(pk_of_default_user))
def __init__(self, user, *args, **kwargs):
super(TransactionForm, self).__init__(*args, **kwargs)
self.fields['category'] = forms.ModelChoiceField(
queryset=Category.objects.filter(user=user))
update: in class based views you can add extra parameter to form init in get_form_kwargs:
class TransUpdateView(UpdateView):
#...
def get_form_kwargs(self):
kwargs = super(YourView, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs