From my views:
class SongCreate(CreateView):
model = Song
fields = ['album', 'name']
My functionality of adding a song (this) to an album is inside the details template of an album A. However, I want the input only be the name and not the album anymore since the song's album should automatically be "A." How do I make the code above behave such?
From my urls:
url(r'album/(?P<pk>[0-9]+)/song/add/$', views.SongCreate.as_view(), name='song-add')
You can use the get_initial method:
class SongCreate(CreateView):
model = Song
fields = ['album', 'name']
def get_initial(self):
return {
'album': Album.objects.get(id=self.kwargs.get('pk')),
}
Or you can use the form_valid method:
class SongCreate(CreateView):
model = Song
fields = ['name']
def form_valid(self, form):
form.instance.album = Album.objects.get(id=self.kwargs.get('pk'))
return super(SongCreate, self).form_valid(form)
Related
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 !!!
So I have two Models that I want to relate with a ForeignKey. One of the ModelForms I want to have it's Foreign Key field pre populated before the model gets created. The info from the ForeignKey comes from a ListView (List of Cars that belong to clients) template.
MODELS.PY
class ClientCar(models.Model):
license_plate = models.CharField(max_length=20, unique=True, name='license_plate')
def__str__:
pk = self.pk
license_plate = self.license_plate
return f"pk:{pk} license_plate {license_plate}"
class CarDetail(model.Model):
car = models.ForeignKey(ClientCar, on_delete=models.CASCADE, null=False)
detail = models.CharField(max_length=40, null=False)
So the ListView template will have the basic crud of the Car model but I also want to add a "Wash button", the wash button will pass the selected Car's pk to the CarDetail Form template. It is here where I am having issues. I can Query the PK of the car from Kwargs but I can't seem to populate the Form's field with that query or have it render on the template.
VIEWS.PY
class WashService(LoginRequiredMixin, CreateView):
model = CarDetail
form_class = WashServiceForm
template_name = 'service_app/standard_wash_form.html'
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(WashService, self).get_form_kwargs(*args, **kwargs)
ctd = ClientCar.objects.filter(pk=self.kwargs.get('pk')).values('license_plate')
kwargs['initial']['car'] = ctd
return kwargs
I have researched this and came to the understanding that in the Form for creating this model I have to overwrite the _ _ init _ _ function, I'm not really sure how to solve this since I don't know how to call the kwargs passed from the Listview template from the forms.py
If you can guide me with some snippets or anything I'm greatful.
Thanks in advance.
I think it makes more sense to simply change what function the ModelChoiceField uses for the choices. We can first make a subclass of ModelChoiceField for the car, to select this by license plate:
from django import forms
class CarByLicensePlateChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.license_plate
Then in your WashServiceForm we can use this field:
class WashServiceForm(forms.ModelForm):
car = CarByLicensePlateChoiceField(queryset=Car.objects.all())
class Meta:
model = Car
fields = ['car', 'detail']
In your CreateView, you can then populate the car with the Car that belongs to the given primary key:
from django.shortcuts import get_object_or_404
class WashService(LoginRequiredMixin, CreateView):
model = CarDetail
form_class = WashServiceForm
template_name = 'service_app/standard_wash_form.html'
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs(*args, **kwargs)
initials = kwargs.setdefault('initial', {})
intial['car'] = get_object_or_404(Car, pk=self.kwargs['pk'])
return kwargs
I have a FormView with a get_initial method which I am trying to use to populate the form. I am trying to get the EmployeeTypes of the receiver of the memo as values in the form.
def get_initial(self):
initial = super(NotificationView, self).get_initial()
users = Memo.objects.filter(id=self.kwargs['pk']).values('receiver__employee_type')
initial['receiving_groups'] = users
return initial
There are 2 issues here..
This returns a Queryset which looks like: <QuerySet [{'receiver__employee_type': 'Bartender'}, {'receiver__employee_type': 'Supervisor'}]> when I really need the fields in the form to be the EmployeeType itself.
Most importantly - the form isn't even rendering these fields.
Here is the form just in case:
class MemoNotificationForm(forms.Form):
class Meta:
fields = [
'receiving_groups'
]
receiving_groups = forms.MultipleChoiceField(
required=False,
widget=forms.CheckboxSelectMultiple)
How do I populate the fields of the form?
EDIT:
class Memo(models.Model):
receiver = models.ManyToManyField(EmployeeType, related_name='memos_receiver')
class EmployeeType(models.Model):
"""Stores user employee type."""
employee_type = models.CharField(
max_length=32,
unique=True)
Having a Meta on a forms.Form doesn't do anything, this is used for ModelForms
If receiving_groups should be choices of EmployeeType then it should be a ModelMultipleChoiceField
class MemoNotificationForm(forms.Form):
receiving_groups = forms.ModelMultipleChoiceField(
EmployeeType.objects.all(),
widget=forms.CheckboxSelectMultiple
)
Then you should be passing instances, or a queryset of the model in the initial
def get_initial(self):
initial = super(NotificationView, self).get_initial()
initial['receiving_groups'] = EmployeeType.objects.filter(memo__id=self.kwargs['pk'])
return initial
EDIT:
As a ModelForm this could look like so
class MemoNotificationForm(forms.ModelForm):
class Meta:
model = Memo
fields = ('receiver', )
View:
class NotificationView(FormView);
form_class = MemoNotificationForm
def get_form_kwargs(self):
kwargs = super(NotificationView, self).get_form_kwargs()
kwargs['instance'] = get_object_or_404(Memo, id=self.kwargs['pk'])
return kwargs
While #lain Shelvington is correct in the process he used to produce the form results, I had to do a little editing to make the code operate correctly...
def get_initial(self):
initial = super(NotificationView, self).get_initial()
receivers = Memo.objects.filter(id=self.kwargs['pk']).values_list('receiver')
initial['receiving_groups'] = EmployeeType.objects.filter(employee_type=receivers)
return initial
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
Django 1.9.7
Updating and creation are more or less similar operations. Sometimes I would like to add JavaScript events as widget attrs. For example, users select a gender. Depending on that I'd like to show or hide maiden name. This is just an example of some operation common to UpdateView and CreateView.
I tried to organize it as a mixin, but failed: UpdateView and CreateView both use FormMixin. If I organize another mixin inheriting from FormMixin, I get a clash.
Could you help me understand how to cope without repeating the code?
class PersonUpdateView(UpdateView):
model = Person
fields = ['gender', 'last_name']
class PersonCreate(CreateView):
model = Person
fields = ['gender', 'last_name']
redirect_name = "people"
field_attrs = {'gender': {'onchange':"alert('G')"},
'last_name': {'onclick': "alert('LN')"},
}
def get_form(self, form_class=None):
form = super(PersonCreate, self).get_form(form_class)
for key, value in self.field_attrs.items():
form.fields[key].widget.attrs = value;
return form
Your mixin should be a simple class:
class CreateUpdateMixin(object):
model = Person
fields = ['gender', 'last_name']
field_attrs = {'gender': {'onchange':"alert('G')"},
'last_name': {'onclick': "alert('LN')"},
}
Then you use it like so:
class PersonUpdateView(CreateUpdateMixin, UpdateView):
pass
class PersonCreate(CreateUpdateMixin, CreateView):
redirect_name = "people"
def get_form(self, form_class=None):
form = super(PersonCreate, self).get_form(form_class)
for key, value in self.field_attrs.items():
form.fields[key].widget.attrs = value;
return form