Django 3.0.8 Field.disable UpdateView - django

For example I have a EntryUpdateForm that inherits from UpdateView that updates some data on a model. Now I'd like to disable certain fields. From the Django documentiation I'm not sure where exatcly to put the Field.disable attribute to disable a certain field on a form.
forms.py
class EntryUpdateForm(UpdateView):
class Meta:
model = Entry
fields = ["material", "shape", "diameter", "taken_from", "moved_to", "quantity"]
views.py
class EntryUpdateView(LoginRequiredMixin, EntryUpdateForm):
model = Entry
fields = ["material", "shape", "diameter", "taken_from", "moved_to", "quantity"]
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
I'm not even sure if it's possible to do this if I'm inheriting from the UpdateView, at least easly.

class EntryUpdateForm(UpdateView):
material = forms.CharField(widget=forms.TextInput(attrs={'readonly':'True'}))
class Meta:
model = Entry
fields = ["material", "shape", "diameter", "taken_from", "moved_to", "quantity"]
Replace material with whichever field you want to disable and use the appropriate widget

Thanks to a comment from mursalin I managed to get it to work.
forms.py
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ["material", "shape", "diameter", "taken_from", "moved_to", "quantity"]
material = forms.ChoiceField(disabled=True)
shape = forms.ChoiceField(disabled=True)
diameter= forms.CharField(disabled=True) # add whichever field you want to disable
class EntryUpdateForm(UpdateView):
class Meta:
model = Entry
views.py
class EntryUpdateView(LoginRequiredMixin, EntryUpdateForm):
model = Entry
form_class = EntryForm # pass the form in the view to get it to change
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)

Related

Create form to change relationship from related model's form

I have two models:
class Thing(forms.ModelForm):
class Owner(forms.ModelForm):
thing = models.OneToOneField(Thing)
I want to add a form to change the owner in Thing's UpdateView. I can do it like this:
class ThingForm(forms.ModelForm):
owner = forms.ModelChoiceField(
queryset=Owner.objects.all(),
)
class Meta:
model = Thing
fields = '__all__'
And then process the result inside form_valid() method. But isn't there a more direct approach for this, where i just add this to the fields of the form?
UPDATE
So I ended up doing it like this:
class ThingUpdateView(UpdateView):
model = Thing
form_class = ThingForm
def get_initial(self):
initial = super(ThingUpdateView, self).get_initial()
try:
initial['owner'] = self.object.owner
except Thing.owner.RelatedObjectDoesNotExist:
pass
return initial
def form_valid(self, form):
self.object = form.save(commit=False)
owner = form.cleaned_data['owner']
owner.thing = self.object
owner.save(update_fields=['thing'])
self.object.save()
return redirect(self.object.get_absolute_url())
Maybe there's a better way.

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)

Django - Createview form_valid object.id error

I'm trying to create a form where the object created (a project) has a relationship with another model (the channel). The problem is I can't workout how to call the channel's primary key for the project's relationship.
Models.py:
class Project(models.Model):
channel = models.ForeignKey(
'Channel',
on_delete=models.CASCADE,
)
Views.py:
class ProjectCreate(CreateView):
model = Project
fields = ['name', 'description']
def form_valid(self, form):
Project = form.save(commit=False)
form.instance.channel = Channel.objects.get(id=self.kwargs['channel'])
Project.channel = channel
return super(ProjectCreate, self).form_valid(form)
I think something else needs to be added to the forms.py file as well:
Forms.py:
class ProjectForm(forms.Form):
name = forms.CharField(max_length=50)
description = forms.CharField(widget=forms.Textarea)
Firstly, you should use a ModelForm so that you can save it to create the instance. Don't include channel in the fields, because you're going to set it in the view.
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['name', 'description']
Then, assuming that your url pattern is correctly configured to include the channel, all you need to do is set the channel on the form instance and call the parent class' form_valid method.
def form_valid(self, form):
form.instance.channel = Channel.objects.get(id=self.kwargs['channel'])
return super(ProjectCreate, self).form_valid(form)

Saving the form while there are two ForeignKeys,

I have two models as shown below
class college(models.Model):
name = models.CharField(max_length=256)
class education(models.Model):
author = models.ForeignKey('auth.User')
school = ForeignKey(college)
field = models.CharField(max_length=200)
startyear = models.IntegerField(blank =True,null = True)
endyear = models.IntegerField(blank =True,null = True)
Views as shown below
class EducationListView(ListView):
template_name = 'education.html'
def get_queryset(self):
return education.objects.filter(author__username=self.request.user.username).order_by('-startyear')
class EducationCreate(CreateView):
model = dupeducation
fields = ('school','field','startyear','endyear')
template_name = 'education_form.html'
def form_valid(self, form):
form.instance.author = self.request.user
obj,created = college.objects.get_or_create(name=form['school'])
obj.save()
form.instance.school = obj
return super(EducationCreate, self).form_valid(form)
class EducationUpdate(UpdateView):
model = education
fields = ('school','field','startyear','endyear')
template_name = 'education_form.html'
def form_valid(self, form):
form.instance.author = self.request.user
return super(EducationUpdate, self).form_valid(form)
class EducationDelete(DeleteView):
model = education
success_url = reverse_lazy('education')
I am unable to save the form. It's throwing an error to the school field like this "Select a valid choice. That choice is not one of the available choices.".
My goal is to take input for the school field and check that field with get_object_or_create . If that object does not exist, create it and attach it to the school field.
If you debug, you'll see that save() is not being reached. Your problem is in the Field validation.
What you need to do is to override the clean_<field>() method called before any object is saved.
You can read more about it here: Django how to override clean() method in a subclass of custom form?
While overriding clean_school(), you will be able to add the value to the database, and later, in save(), simply make the attribution.