in function based view it's easy to pass parameters to form instances as form = FormName(user_id=..) and do other staffs, but I'm wondering how to do this in django update view It's my view
class MedicalrecordUpdate(UpdateView):
model = MedicalRecords
form_class = EditMedicalRecord
success_url = "."
template_name = "medicalrecord/edit_medicalrecord.html"
# ?? no idea how to pass user id to EditMedicalRecord form
forms.py
class EditMedicalRecord(forms.ModelForm):
def __init__(self, *args, **kwargs):
user_id = kwargs.pop("user_id")
super(EditMedicalRecord, self).__init__(*args, **kwargs)
...
...
You need to override get_form_kwargs:
class MedicalrecordUpdate(UpdateView):
model = MedicalRecords
form_class = EditMedicalRecord
success_url = "."
template_name = "medicalrecord/edit_medicalrecord.html"
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({'user_id': self.kwargs.get('user_id')}) # self.kwargs is the kwargs passed to the view
return kwargs
Related
I have created Two decorator to block anyone to Access to specific content
like:
#method_decorator(login_required(login_url='core:login'), name='dispatch')
#method_decorator(allowed_users(allowed_roles=['writer']), name='dispatch')
class BookDeleteView(BSModalDeleteView):
model = Book
template_name = 'book/book_delete.html'
success_message = 'Success: book was deleted.'
success_url = reverse_lazy('core:book_list')
i want to create decorator seems like this
book=Book.objects.get(id=pk)
if request.user==book.writer.profile.user:
If you want to use a decorator:
def writers_only(function):
#wraps(function)
def wrap(request, *args, **kwargs):
if request.user == Book.objects.get(id=kwargs.get('pk')).writer.profile.user:
return function(request, *args, **kwargs)
else:
# Do something else
return wrap
Then add this to your class based view:
# Other decorators
#method_decorator(writers_only, name='dispatch')
class BookDeleteView(BSModalDeleteView):
# Your code
Otherwise you can also override BookDeleteView.get_object (you can create a mixin to reuse this implementation of get_object in various views):
#method_decorator(login_required(login_url='core:login'), name='dispatch')
#method_decorator(allowed_users(allowed_roles=['writer']), name='dispatch')
class BookDeleteView(BSModalDeleteView):
model = Book
template_name = 'book/book_delete.html'
success_message = 'Success: book was deleted.'
success_url = reverse_lazy('core:book_list')
def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs)
if obj.writer.profile.user != self.request.user:
raise PermissionDenied() # Or do something else
return obj
You don't need a decorator for that. What you need is queryset defined on your model view that will restrict the query:
class BookDeleteView(BSModalDeleteView):
def get_queryset(self):
return self.model.objects.filter(user=self.request.user)
In case it has to be done for delete only you may also set it dynamically depending on request:
class BookDeleteView(BSModalDeleteView):
def get_queryset(self):
if self.request.method == 'DELETE':
return self.model.objects.filter(user=self.request.user)
return self.model.objects.all()
I want to filter form fields querysets based on the user selected. Therefore, I want to pass user as argument to the form in order to filter fields querysets in the form's __init__ method. When I pass any arguments to the form I get the following error.
class UserDetailView(LoginRequiredMixin, FormMixin, DetailView):
model = TbUser
form_class = TbPeopleEntranceRightForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = TbPeopleEntranceRightForm(user=self.object)
context['form'] = form
return context
__init__() got an unexpected keyword argument 'user'
how do I pass the argument correctly, and how I get it in the __init__ form method?
Update:
class TbPeopleEntranceRightForm(forms.ModelForm):
def __init__(self, user, **kwargs):
super().__init__(**kwargs)
print(user)
# Use `self.user` here or in some other methods.
__init__() missing 1 required positional argument: 'user'
don't do it in get_context_data, it's made for something else.
Use get_form_kwargs instead:
class UserDetailView(LoginRequiredMixin, FormMixin, DetailView):
model = TbUser
form_class = TbPeopleEntranceRightForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["user"] = self.object
return kwargs
And in your forms.py:
def __init__(self, user=None, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
You need to add the parameter to the form's __init__ method:
class TbPeopleEntranceRightForm(forms.ModelForm):
...
def __init__(self, user=None, **kwargs):
super().__init__(**kwargs)
self.user = user
# Use `self.user` here or in some other methods.
Also, the correct way to then pass the user argument to the form is to override get_form_kwargs in the view, like #MojixCoder showed.
I have a update view:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
def dispatch(self, *args, **kwargs):
return super(GeneralUserUpdateView, self).dispatch(*args, **kwargs)
def post(self, request, pk, username):
self.pk = pk
self.username = username
self.gnu = GeneralUser.objects.get(pk=self.pk)
#form = self.form_class(request.POST, request.FILES)
return super(GeneralUserUpdateView, self).post(request, pk)
def form_valid(self, form, *args, **kwargs):
self.gnu.username = form.cleaned_data['username']
self.gnu.email = form.cleaned_data['email']
self.gnu.first_name = form.cleaned_data['first_name']
self.gnu.last_name = form.cleaned_data['last_name']
self.gnu.address = form.cleaned_data['address']
self.gnu.save()
return redirect("user_profile", self.pk, self.username)
Here in this view I want to pass a context like:
context['picture'] = GeneralUser.objects.get(pk=self.pk)
I did trying get_context_data but I cant access pk in there..
Am I doing the update right?? How can I pass that context in there??
You shouldn't be overriding post at all. All of that logic should happen in get_context_data.
In fact, none of your overrides are needed. Everything that you do in form_valid will be done already by the standard form save. And overriding dispatch just to call the superclass is pointless.
Your view should look like this only, with no overridden methods at all:
class GeneralUserUpdateView(UpdateView):
model = GeneralUser
form_class = GeneralUserChangeForm
template_name = "general_user_change.html"
context_object_name = 'picture'
(although it seems a little odd that you want to refer to an instance of GeneralUser as "picture").
Edit to redirect to a specific URL, you can define get_success_url:
def get_success_url(self):
return reverse("user_profile", self.kwargs['pk'], self.kwargs['username'])
I am working on a python/django application. In my application there are 2 tables Store and Ad. That have many to many relation.
Class Store:
ads = models.ManyToManyField(Ad, null=True, blank=True)
Class Store:
ads = models.ManyToManyField(Ad)
I have tested it with both implementations given above but when i save my store without selecting an ad it gives me error:
ads: This field is required.
How can i set ads optional here???
View:
class StoreView(FormView):
form_class = StoreForm
success_url = "/"
template_name = 'store.html'
def __init__(self):
super(StoreView, self).__init__()
self.store = None
def get_form_kwargs(self):
kwargs = super(StoreView, self).get_form_kwargs()
kwargs['current_user'] = self.request.user
if 'store_id' in self.kwargs:
self.store = Store.objects.get(id=self.kwargs['store_id'])
kwargs['instance'] = self.store
kwargs['request'] = self.request
return kwargs
def get_context_data(self, **kwargs):
context = super(StoreView, self).get_context_data(**kwargs)
context['store_info'] = self.store
return context
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(StoreView, self).dispatch(*args, **kwargs)
def form_invalid(self, form):
return super(StoreView, self).form_invalid(form)
def form_valid(self, form):
self.object = form.save()
return super(StoreView, self).form_valid(form)
Form:
class StoreForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.fields['ads'] = forms.ModelMultipleChoiceField(
queryset=Ad.objects.filter(type=13),
widget=forms.CheckboxSelectMultiple,
label='Ads associated with this store'
)
def save(self, commit=False):
store = super(StoreForm, self).save(commit=True)
return store
class Meta:
model = Store
add required=False in definition ads field in the form. When you override a field in model form, no attributes are inherited from the model. You have to add all constraints to it like max_length, required etc.
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