Set form values on page load - django

How to populate a form from DB based on the pk? So if the url is http://demo.com/edit-voucher/123456, how do I get the values of voucher entry 123456 into the form?
The form displays, but don't know how to populate it...
urls.py:
url(r'^edit-voucher/(?P<pk>[\d]+)', reports.EditVoucherView.as_view()),
forms.py:
class EditVoucherForm(forms.ModelForm):
class Meta:
model = Vouchers
fields = ['event_name', 'valid_start', 'valid_end', 'duration']
views.py:
class EditVoucherView(LoginRequiredMixin, GroupRequiredMixin, FormView):
template_name = 'edit_voucher.html'
group_required = u'voucherEdit'
form_class = EditVoucherForm

You can use UpdateView instead of FormView:
class EditVoucherView(LoginRequiredMixin, GroupRequiredMixin, UpdateView):
template_name = 'edit_voucher.html'
group_required = u'voucherEdit'
form_class = EditVoucherForm
model = Vouchers

It looks like you can access the pk of the form in your template as it is in the url. If you use pycharm, try using the debugger to see if the pk value is available in the template.

Related

How to get object uid from previous page in Django web-app?

I`m trying to make a CreateView form that takes the UID of the object as a foreign key from the previous page.
Here I got DetailView of Plan model:
class PlanDetailView(IsStaffPermissionMixin, DetailView):
model = Plan
template_name = "backoffice/plans/plan_detail.html"
context_object_name = 'plan'
def get_object(self):
uid = self.kwargs.get("uid")
return get_object_or_404(Plan, uid=uid)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
practice_sessions = PracticeSession.objects.all().filter(plan__uid=self.kwargs.get("uid"))
context['practice_sessions'] = practice_sessions
return context
And here I got a PracticeSession CreateView:
class PracticeSessionCreateView(IsStaffPermissionMixin, CreateView):
model = PracticeSession
template_name = "backoffice/practice_session/practice_session_create.html"
fields = ['uid', 'title', 'plan', 'snippet', 'welcome_content', 'done_content', 'order_index', ]
success_url = reverse_lazy('practice-sessions')
As you understand, PracticalSession contains Foreign Key for the Plan model
Now I want that when I click on the button to create a PracticalSession (the picture below), I create a form in which the plan field already contains a "uid" of Plan from the page of which I create a new PracticalSession
My Form:
class PracticeSessionCreateForm(ModelForm):
class Meta:
model = PracticeSession
fields = '__all__'
Big THANK YOU In advance !!!

How to use Django function based view to update a model?

I used a class based view to update a user profile using this code
class EditProfileViewClass(generic.UpdateView):
model = UserProfile
fields = ['bio', 'profile pic']
template_name = 'users/update.html'
success_url = reverse_lazy('home')
path('profile/<int:pk>/update', EditProfileViewClass.as_view(), name="profile"),
Your Profile
the issue right now is, Instead of having the url like the one above, I want it to be like
path('profile/<str:username>/update', EditProfileViewClass.as_view(), name="profile"),
but unfortunately I get an attribute error saying:
Generic detail view EditProfileView must be called with either an object pk or a slug in the URLconf.
So I tried making a function based view so I can get the "username" from the url, doing that didn't allow me to get the form I needed to update the specific username.
Any help would be great. Thanks.
In your EditProfileViewClass view you can add pk_url_kwarg or slug_url_kwarg.
class EditProfileViewClass(UpdateView):
model = UserProfile
fields = ['bio', 'profile pic']
template_name = 'users/update.html'
success_url = reverse_lazy('home')
pk_url_kwarg = 'username'
slug_url_kwarg = 'username'
You can use a class-based view, you only need to update the the slug_field (which determines on what should be used), and the slug_url_kwargs:
class EditProfileViewClass(UpdateView):
model = UserProfile
fields = ['bio', 'profile_pic']
template_name = 'users/update.html'
success_url = reverse_lazy('home')
slug_field = 'user__username'
slug_url_kwarg = 'username'
This will thus take the username parameter of the URL, and it will filter the queryset to only retrieve a UserProfile that is linked to a user with that username.

How to filter Django's foreignKey form dropdown

I have a form that is used to edit (update) a record, and the Author field is automatically a dropdown, which is great, but how do you filter this list?
For example, the dropdown is populated with the entire user list. How can I filter this list so that it only shows the items where isDevice == True?
accounts/models.py
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
isDevice = models.BooleanField(default = False)
...
builds/models.py
class BuildQueue(models.Model):
Author = models.ForeignKey(CustomUser,blank=True, null= True, on_delete=models.CASCADE)
...
forms.py
class BuildQueueEditForm(forms.ModelForm):
class Meta:
model = BuildQueue
fields = ['Author','project', 'customer',]
views.py
class buildQueueEdit(LoginRequiredMixin,UpdateView):
model = BuildQueue
form_class = BuildQueueEditForm
template_name = 'buildQueue_edit.html'
Since UpdateView inherited also from FormMixin, in your buildQueueEdit you can override get_form, where form is instantiated and exactly where you can modify the form's field's queryset.
class buildQueueEdit(LoginRequiredMixin,UpdateView):
model = BuildQueue
form_class = BuildQueueEditForm
template_name = 'buildQueue_edit.html'
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['Author'].queryset = CustomUser.objects.filter(isDevice=True)
return form
UPDATE
If you want to change text displayed in your dropdown you can override choises instead of queryset. It worked for me.
form.fields['Author'].choices = [(item.id, item.equipmentName) for item in CustomUser.objects.filter(isDevice=True)]

django fill form field automatically from context data

I have a form attached to a DetailedView and its working fine when saved. I would like the form field(position) to be prepopulated with the value coming from the slug of the detailed view(e.g jobs/human-resource-manager). The Model of the form field has a Foreignkey to the JobPost model. Need help. Part of my view looks like this
class JobsDetailView(DetailView):
model = JobPost
template_name = 'job_post-detail.html'
def get_context_data(self, **kwargs):
context = super(JobsDetailView, self).get_context_data(**kwargs)
context['position'] = JobPost.objects.order_by('position')
context['job_app_form'] = JobsForm()
return context
foms.py
from django import forms
from job_post.models import JobsApplied
class JobsForm(forms.ModelForm):
class Meta:
model = JobsApplied
fields = '__all__'
def form_valid(self, form):
form.instance.customuser = self.request.user
return super().form_valid(form)
I'm assuming you do not want your users to be able to interact with or change these prefilled values.
I'm making a comments/review model and I want it to automatically link reviews to the people they are about
models.py
class Review(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
...
I hide the person field in the ReviewsForm to prevent user input by either omitting it from the 'fields' or adding it to an 'exclude'.
forms.py
class ReviewsForm(forms.ModelForm):
class Meta:
model = Review
fields = ('rating', 'summary', 'review_text')
Then, when processing the form in the view, I use commit=False so I can manipulate field values before saving to the database.
Include prefilled values, save and then redirect the user wherever is ideal
views.py
def person(request, area_slug, category_slug, person_id):
...
if form.is_valid():
pending_review = form.save(commit=False)
pending_review.person = Person.objects.get(pk = person_id)
pending_review.save()
return HttpResponseRedirect(...)
django fill form field automatically from context data for django form and django formsets
For formsets in forms.py
StoreRequestAccessoryUpdateFormSet = forms.modelformset_factory(StoreRequestAccessory, form=StoreRequestAccessoryUpdateForm, exclude=["storeRequestId"], can_delete=True)
In get_context_data you can add it as you like for django
class StoreRequestUpdateView(LoginRequiredMixin, UpdateView):
template_name = "Inventory/Stock/StoreRequest/StoreRequestUpdateView.html"
model = StoreRequest
fields = ["fromStoreId", "toStoreId", "reference", "status", "remark"]
def get_context_data(self, **kwargs):
context = super(StoreRequestUpdateView, self).get_context_data(**kwargs)
print(self.object.pk)
context.update({
# "StoreRequestForm": context.get("form"),
"StoreRequestForm": StoreRequestUpdateForm(instance=StoreRequest.objects.get(id=self.object.pk)),
"StoreRequestAccessoryForm": StoreRequestAccessoryUpdateFormSet(
queryset=StoreRequestAccessory.objects.filter(storeRequestId=self.object.pk),
prefix="storereq_accessory_form"),
})
return context

Pass url parameter to Django ModelForm without rendering it as input on form

I have a url /<subject_id>/comments/new/ which renders a Django ModelForm. I am using a view class derived from FormView to process the form. I wish to do the following:
subject_id should not appear on the rendered form.
subject_id should be added to the form prior to is_valid() being called, or if this is not possible should be added to the Comment instance.
forms/comment_form.py:
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ['text']
views.py:
class CommentCreate(FormView):
form_class = CommentForm
def form_valid(self, form):
# Do some stuff to the validated Comment instance
# Maybe save the comment, maybe not
return super().form_valid(form)
How do I do this? If I add subject_id as a field in CommentForm then it appears on the rendered form. If I don't then the form is instantiated with subject_id present from `self.kwargs['subject_id'] and complains of an "unexpected keyword argument".
After some hunting around in the docs I have discovered that the correct answer is to use the get_form() method to pre-populate the form with the data that I don't want to appear on the form, but that needs to be present for validation.
class CommentCreate(FormView):
form_class = CommentForm
def get_form(self):
self.subject= get_object_or_404(Subject, id=self.kwargs['subject_id'])
partial_comment = Comment(user=self.request.user, subject=self.subject)
form = CommentForm(**self.get_form_kwargs(), instance=partial_comment)
return form
You can remove subject_id from form fields:
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ['text']
And add it to new comment object in form_valid method like this:
class OrderCreate(FormView):
form_class = CommentForm
def form_valid(self, form):
subject_id = self.kwargs['subject_id']
subject = Subject.objects.get(id=subject_id)
form.instance.subject_id = subject
return super().form_valid(form)