get form input value from form_class in views - django

How do I access the company_id field in form input in the class based views
forms.py
class CompanyProductForm(forms.Form):
company_id = forms.IntegerField()
I tried overriding the form_valid() but didn't work out.
also I want to convert 'obj' queryset to a python list and then append it to products.
view.py
class CompanyProduct(LoginRequiredMixin, UserPassesTestMixin, FormView):
template_name = 'company_product.html'
form_class = CompanyProductForm
products = []
def test_func(self):
return self.request.user.is_staff
def post(self, request, *args, **kwargs):
self.products = []
def form_valid(self, form):
id = form.cleaned_data['company_id']
return super(CompanyProduct, self).form_valid(form)
obj = Product.objects.filter(company_id=id)
return render(request, 'product_download.html',{'product':self.products,
'num':len(self.products)})
Error:
TypeError at /upload/company_product/
int() argument must be a string or a number, not 'builtin_function_or_method'

By overriding the post method with just an assignment you have disabled all the other actions that are supposed to happen on post, such as validating the form. You should remove that method altogether - define that list somewhere else, such as in form_valid.

Related

Django UpdateView user validation not working

Hello guys I have this update view where I am not able to validate the user(owner). How to tweak this to add that bit too.? Please have a look at the code.
class StoreInfoView(UpdateView, LoginRequiredMixin):
model = Store
template_name = 'store/store_information.html'
form_class = StoreInfoForm
success_message = 'Updated'
success_url = reverse_lazy('store:store_home')
def get_object(self, queryset=None):
obj = Store.objects.get(id=self.kwargs['id'])
if obj.user != self.request.user:
raise PermissionDenied('You Don\'t have permission to edit!')
return obj
def get(self, *args, **kwargs):
self.object = Store.objects.get(id=self.kwargs['id'])
form_class = self.get_form_class()
form = self.get_form(form_class)
context = self.get_context_data(object=self.object, form=form)
return self.render_to_response(context)
Thanks
Instead of overriding like this, you can simply override get_queryset() method. Like this:
class StoreInfoView(UpdateView, LoginRequiredMixin):
model = Store
template_name = 'store/store_information.html'
form_class = StoreInfoForm
success_message = 'Updated'
success_url = reverse_lazy('store:store_home')
def get_queryset(self, *args, **kwargs):
queryset = super().get_queryset(*args, **kwargs)
return queryset.filter(user=self.request.user)
In this way, non-owner users will get 404 error when they try to update.
Also, you do not need to override any other methods like get() and get_object() method.
The issue to your problem is the order of inheritance. When you will go through the official docs for LoginRequiredMixin, you will find this
This mixin should be at the leftmost position in the inheritance list.
Please update your code to this
class StoreInfoView(LoginRequiredMixin, UpdateView):
model = Store
template_name = 'store/store_information.html'
form_class = StoreInfoForm
success_message = 'Updated'
success_url = reverse_lazy('store:store_home')
...
Notice, now LoginRequiredMixin is put before the UpdateView. This should resolve your query.
I hope it helps. :)

Passing and accessing value in Django form

I'm trying to pass info to my form and I have a bit of a struggle with that. My code looks as follows:
views.py
class ObjectUpdateView(UpdateView):
template_name = 'manage/object_form.html'
form_class = ObjectEditForm
def get_success_url(self):
#...
def form_valid(self, form):
return super(ObjectUpdateView, self).form_valid(form)
def get_object(self):
return get_object_or_404(Room, pk=self.kwargs['object_id'])
def get_form_kwargs(self, **kwargs):
objectid = self.kwargs['object_id']
object = Object.objects.get(id = objectid)
container = object.container
kwargs['container_id'] = container.id
return kwargs
forms.py
class ObjectEditForm(forms.ModelForm):
class Meta:
model = Object
fields = ['TestField']
def __init__(self, *args, **kwargs):
super(ObjectEditForm, self).__init__(*args, **kwargs)
self.Container_id = kwargs.pop('container_id')
form_page.html
{{fomr.kwarg.Container_id}}
As you can see I'd like to access Container_id value in my form_page.html. Unfortunately, nothing is there. What I also noticed, that with __init__ I had to add, now values are empty in my form. Before I added __init__ all values were properly passed (well, except Container_id).
Could you recommend how I can pass such value to be accessed in the form template?
You can render this with:
{{ form.Container_id }}
In your form you should first pop the container_id from the kwargs, like:
class ObjectEditForm(forms.ModelForm):
class Meta:
model = Object
fields = ['TestField']
def __init__(self, *args, **kwargs):
# first pop from the kwargs
self.Container_id = kwargs.pop('container_id', None)
super(ObjectEditForm, self).__init__(*args, **kwargs)
Use the context over the form
That being said, it is a bit strange that you pass this to the form, and not add this to the context data. You can simplify your view a lot to:
class ObjectUpdateView(UpdateView):
template_name = 'manage/object_form.html'
pk_url_kwarg = 'object_id'
form_class = ObjectEditForm
def get_success_url(self):
#...
def get_context_data(self, **kwargs):
objectid = self.kwargs['object_id']
object = Object.objects.get(id = objectid)
context = super().get_context_data()
context.update(container_id=object.container_id)
return context
Django automatically fetches a single element based on the pk_url_kwarg [Django-doc]. You only need to set it correctly, so here that is the object_id.
In that case, we can simply render this with:
{{ container_id }}
and you do not need to store this in the form.

Django: access form argument in CreateView to pass to get_success_url

I use CreateView to let a user create a Piece. The Piece will automatically be assigned an id. After the user created the Piece I would like to redirect using get_success_url to another CreateView to add Versions of the Piece.
First of all, I do not know where the id of the Piece comes from (since it is generated automatically; I imagine this is the row number of the Piece in the model). How can I access this id to pass it to get_success_url?
The get_context_data method in CreateView seems not to be able to get the Piece id.
views.py
class PieceCreate(LoginRequiredMixin, CreateView):
model = Piece
fields = ['title', 'summary', 'created', 'piece_type']
initial = {'created': datetime.date.today()}
def form_valid(self, form):
form.instance.creator = Creator.objects.get(user=self.request.user)
return super(PieceCreate, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(PieceCreate, self).get_context_data(**kwargs)
return context['id']
def get_success_url(self):
return reverse_lazy('pieceinstance-create', kwargs={'pk': self.get_context_data()})
urls.py
path('pieceinstance/create/<int:pk>', views.PieceInstanceCreate.as_view(), name='pieceinstance-create')
The instance that is constructed in the CreateView can be accessed with self.object [Django-doc], so you can obtain the primary key with self.object.pk:
class PieceCreate(LoginRequiredMixin, CreateView):
model = Piece
fields = ['title', 'summary', 'created', 'piece_type']
initial = {'created': datetime.date.today()}
def form_valid(self, form):
form.instance.creator = Creator.objects.get(user=self.request.user)
return super(PieceCreate, self).form_valid(form)
def get_success_url(self):
return reverse_lazy('pieceinstance-create', kwargs={'pk': self.object.pk})
I would advice not to override the get_context_data function that way: first of all, the contract specifies that it should return a dictionary, so not an id, and multiple functions make use of this, and expect the contract to be satisfied.

Filtering a model in a CreateView with get_queryset

I'm trying to filter a model with get_queryset() and it seems to work in the view but not in the template.
My view :
class FolderCreate(CreateView):
fields = ['name', 'parent']
template_name = 'Form/folder_create.html'
def get_queryset(self):
folders = Folder.objects.filter(owner=self.request.user)
print folders # ==> return [<Folder: Folder>, <Folder: Another folder>]
return folders
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.owner = self.request.user
return super(FolderCreate, self).form_valid(form)
def get_initial(self):
if self.request.method == 'GET':
foldersUrl = self.request.META['HTTP_REFERER'].split('/')
foldersUrl.pop()
folder = urllib2.unquote(foldersUrl[-1])
try:
return {'parent' : Folder.objects.get(name=folder, owner=self.request.user)}
except Folder.DoesNotExist:
pass
As you can see, folders return two objects related to the session user in get_queryset() : 'Folder' and 'Another folder
Infortunately, the combobox of my template get all the folders, without any filtering.
Any idea ?
The issue here is that get_queryset is not used in a CreateView, as it's meant for filtering the models returned for display in a list or detail view. You want something completely different: you want to filter the choices available in a form field.
To do that you will need to create a custom ModelForm that accepts a user kwarg and filters the queryset accordingly:
class FolderForm(forms.ModelForm):
class Meta:
model = Folder
fields = ['name', 'parent']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(FolderForm, self).__init__(*args, **kwargs)
self.fields['parent'].queryset = Folder.objects.filter(user=user)
and then change your view to use that form and pass in the user parameter:
class FolderCreate(CreateView):
template_name = 'Form/folder_create.html'
form_class = FolderForm
def get_form_kwargs(self):
kwargs = super(FolderCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs

Django: Accessing request in forms.py clean function

Hi Stackoverflow people,
In my clean function in forms.py, I would like to save automatically some information in a session variable. However, I do not seem to get access to the request variable.
All examples for handing over the request variable are based on function based views, but here I am using a class based view.
My forms.py:
from django import forms
from item.models import Item
class CreateItemForm(forms.ModelForm):
class Meta:
model = Item
fields = ('name', 'description')
def __init__(self, request, *args, **kwargs):
self.request = request
super(CreateItemForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(CreateItemForm, self).clean()
if cleaned_data.get("address"):
self.request.session['name'] = cleaned_data.get("name")
else:
raise forms.ValidationError(_('Oops, can\'t find location.'))
return self.cleaned_data
My views.py:
from django.views.generic.edit import FormView
from item.forms import CreateItemForm
class ItemCreate(FormView):
form_class = CreateItemForm
template_name = 'item/item_create.html'
success_url = 'http://www.google.com'
What is the best way to hand over the request variable from the views.py to forms.py?
Thank you for your answer.
You can overwrite the FormMixin's get_form_kwargs method to add the request for to the form's init parameters:
class ItemCreate(FormView):
def get_form_kwargs(self):
kwargs = super(ItemCreate, self).get_form_kwargs()
kwargs.update({
'request' : self.request
})
return kwargs
Overriding the form.get_initial() works for me
class ItemCreate(FormView):
def get_initial(self):
init = super(ItemCreate, self).get_initial()
init.update({'request':self.request})
return init
And in the clean we can access it with form.initial dict
class sampleForm(forms.Form):
...
...
def clean(self):
user_request = self.initial['request']
By the way, we don't need to pop the extra args like suggested above.