I've read previous Q and docs, however still not able to make it work..
I have the following models:
class Process(models.Model):
class Meta:
verbose_name_plural = "Processes"
name = models.CharField(max_length=120)
description = models.CharField(max_length=4)
parent_process = models.ForeignKey('self', related_name="parent_process+", on_delete=models.PROTECT, blank=True, null=True, verbose_name="parent process")
process_activities = models.CharField(max_length = 2048, blank=True, verbose_name="process activites")
owner = models.ForeignKey(User, related_name="owner+", on_delete=models.PROTECT, blank=True, null=True, verbose_name="owner")
def __str__(self):
return "{}".format(self.name)
class ControlTest(models.Model):
history = AuditlogHistoryField()
name = models.CharField(max_length=120)
description = models.CharField(max_length=120)
Now I want to use an accessor to access the name of the process and display in a table (tables.py):
class controltestTable(tables.Table):
class Meta:
hoofdproces = tables.Column(accessor='process.name')
model = ControlTest
fields = ['id',"name", "hoofdproces", "sub_process", 'description', 'control', 'delegate', 'owner', 'reviewer1', 'reviewer2', 'reviewer1_r', 'reviewer2_r', 'delegate_r',
'owner_r', 'reviewer_status', 'status', 'history', 'comments', 'review_comments', 'due_date', 'review1_due_date', 'review2_due_date', 'documentation']
template_name = "django_tables2/bootstrap-responsive.html"
Views.py:
class ControlTestView(SingleTableView, FormView, SingleTableMixin, FilterView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
queryset = kwargs.pop('object_list', None)
if queryset is None:
self.object_list = self.model.objects.all()
context['controltests'] = ControlTest.objects.all()
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
print(form)
if form.is_valid():
instance = form.save(commit=True)
instance.save()
print('valid')
return self.form_valid(form)
else:
print(form.errors)
return self.form_invalid(form)
template_name = "control/ControlTest.html"
model = ControlTest
form_class = ControlTestForm
table_class = controltestTable
success_url = reverse_lazy('controltest')
However, nothing gets displayed in the hoofdproces column :(
How is that possible? What am I doing wrong?
Please help!
Related
When I use UpdateView in Django with a form that has the __init__ method configured to customize the ModelMultipleChoiceField querysets do not load the initial values of the instance?
Some context first, I find myself making an application that manages documents associated to subportals, for that each subportal has associated Service Groups and Dependencies.
I need that when a document is loaded, it can be categorized by Service Groups and Dependencies that are only associated to the subportal. I achieved this by using the __init__ method in the forms.
The problem is that when I need to update the document data, the initial values of the model do not appear.
I show the codes
Models.py
class ServiceGroup(models.Model):
subportal = models.ForeignKey(Subportal, null=True, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=150, null=False, blank=False)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Dependence(models.Model):
subportal = models.ForeignKey(Subportal, null=True, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=150, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class SubportalDocument(models.Model):
def get_upload_to(instance, filename):
return '{}/documents/{}'.format(instance.subportal.title, filename)
subportal = models.ForeignKey(Subportal, null=True, blank=True, on_delete=models.CASCADE)
showcategory = models.OneToOneField(ShowCategory, null=True, blank=True, on_delete=models.CASCADE)
title = models.CharField(max_length=150, null=False, blank=False)
file = models.FileField(upload_to=get_upload_to, null=False, blank=False)
review_date = models.DateField(null=False, blank=True)
review_nro = models.IntegerField(null=False, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
dependences = models.ManyToManyField(Dependence, related_name='dependencesdoc', blank=True)
servicegroups = models.ManyToManyField(ServiceGroup, related_name='servicegroupsdoc', blank=True)
def __str__(self):
return self.title
Forms.py
class SubportalDocumentForm(forms.ModelForm):
class Meta:
model = SubportalDocument
exclude = ['subportal', 'created_at', 'status']
labels = {
'showcategory':'Categoría de Despliegue:',
'title':'Nombre del Documento:',
'file':'Cargar el archivo:',
'review_nro':'Número de Revisión:',
'review_date':'Fecha de Revisión:',
}
widgets = {
'showcategory':forms.Select(attrs={'class':'form-select'}),
'title':forms.TextInput(attrs={'class':'form-control'}),
'file':forms.FileInput(attrs={'class':'form-control'}),
'review_nro': forms.NumberInput(attrs={'class':'form-control'}),
'review_date': forms.DateInput(format=('%d/%m/%Y'),
attrs={'class':'form-control',
'type':'date'}),
}
servicegroups = forms.ModelMultipleChoiceField(
label='Grupos de Servicios:',
queryset=None,
widget=forms.CheckboxSelectMultiple,
)
dependences = forms.ModelMultipleChoiceField(
label='Dependencias:',
queryset=None,
widget=forms.CheckboxSelectMultiple,
)
def __init__(self, *args, **kwargs):
self.subportal = kwargs.pop('subportal')
super(SubportalDocumentForm, self).__init__(*args, **kwargs)
self.fields['servicegroups'].queryset = ServiceGroup.objects.filter(
subportal=self.subportal)
self.fields['dependences'].queryset = Dependence.objects.filter(
subportal=self.subportal)
self.fields['showcategory'].queryset = ShowCategory.objects.filter(
subportal=self.subportal)
self.fields['servicegroups'].widget.attrs.update({
'class': 'form-check-input',
})
self.fields['dependences'].widget.attrs.update({
'class': 'form-check-input',
})
Views.py
class SubportalDocumentUpdateView(UpdateView):
model = SubportalDocument
form_class = SubportalDocumentForm
template_name = 'portal_manager/create_document.html'
def get_form_kwargs(self, *args, **kwargs):
subportal_id = self.get_object().subportal_id
subportal = get_object_or_404(Subportal, id=subportal_id)
kwargs = {
"subportal": subportal,
}
return kwargs
def dispatch(self, request, *args, **kwargs):
id = self.get_object().subportal_id
self.get_form().fields['servicegroups'].queryset = ServiceGroup.objects.filter(subportal_id=id)
self.get_form().fields['dependences'].queryset = Dependence.objects.filter(subportal_id=id)
return super(SubportalDocumentUpdateView, self).dispatch(request, *args, **kwargs)
def get_success_url(self):
id = self.get_object().subportal_id
return reverse_lazy('portal_manager:admin_subportal', kwargs={'id': id})
Urls.py
path('modificar-documento/<int:pk>', views.SubportalDocumentUpdateView.as_view(), name='update_document'),
The result I get is this.
image of the form without the initial values:
Now, if I don't use the __init__ method in the forms to filter the Service Groups and Dependencies by subportal, I get the initial values.
forms.py not init
class SubportalDocumentForm(forms.ModelForm):
class Meta:
model = SubportalDocument
exclude = ['subportal', 'created_at', 'status']
labels = {
'showcategory':'Categoría de Despliegue:',
'title':'Nombre del Documento:',
'file':'Cargar el archivo:',
'review_nro':'Número de Revisión:',
'review_date':'Fecha de Revisión:',
}
widgets = {
'showcategory':forms.Select(attrs={'class':'form-select'}),
'title':forms.TextInput(attrs={'class':'form-control'}),
'file':forms.FileInput(attrs={'class':'form-control'}),
'review_nro': forms.NumberInput(attrs={'class':'form-control'}),
'review_date': forms.DateInput(format=('%d/%m/%Y'),
attrs={'class':'form-control',
'type':'date'}),
}
servicegroups = forms.ModelMultipleChoiceField(
label='Grupos de Servicios:',
queryset=ServiceGroup.objects.all(),
widget=forms.CheckboxSelectMultiple,
)
dependences = forms.ModelMultipleChoiceField(
label='Dependencias:',
queryset=Dependence.objects.all(),
widget=forms.CheckboxSelectMultiple,
)
Ajust Views.py
class SubportalDocumentUpdateView(UpdateView):
model = SubportalDocument
form_class = SubportalDocumentForm
template_name = 'portal_manager/create_document.html'
def dispatch(self, request, *args, **kwargs):
id = self.get_object().subportal_id
self.get_form().fields['servicegroups'].queryset = ServiceGroup.objects.filter(subportal_id=id)
self.get_form().fields['dependences'].queryset = Dependence.objects.filter(subportal_id=id)
return super(SubportalDocumentUpdateView, self).dispatch(request, *args, **kwargs)
def get_success_url(self):
id = self.get_object().subportal_id
return reverse_lazy('portal_manager:admin_subportal', kwargs={'id': id})
Image with the expected result but filtering the Service Groups and Dependencies:
If someone could help me or give me a clue about what is happening, I would appreciate it very much, I have been investigating for a long time and I can't get an answer.
I have two questions in regards to the problem I am currently facing:
Is it best practice in django to overwrite the post method in the CreateView? If it isn't do you write a form _valid function on the CategoryFullForm or in the CreateView and how would it look? The CreateView currently works great, but want to make sure there isn't a better way to do this.
If this is best practice, how would you override the get function in the UpdateView so you would be able to edit the files that relate to the instance being uploaded and even add an additional File? Open to other ways to accomplish this task as well.
models.py
############ CATEGORY MODEL ################
class Category(models.Model):
category_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100, null=True, blank=True)
est_pr_sqft = models.FloatField(blank=True)
est_duration = models.IntegerField(blank=True)
preceding_job = models.CharField(max_length=100, blank=True)
category_notes = models.CharField(max_length=250, blank=True)
category_slug = models.SlugField(max_length=100, unique=True, null=False)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
date_posted = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('category-detail', kwargs={'slug': self.category_slug})
def save(self, *args, **kwargs):
if not self.category_slug:
self.category_slug = slugify(self.name)
return super().save(*args, **kwargs)
class CategoryFiles(models.Model):
category_id = models.ForeignKey(Category, on_delete=models.CASCADE)
document = models.FileField(upload_to="attachments",null=True,blank=True)
uploaded_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
def delete(self, *args, **kwargs):
self.document.delete()
return super().delete(*args, **kwargs)
forms.py
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ['name', 'est_pr_sqft', 'est_duration', 'preceding_job', 'category_notes']
class CategoryFullForm(CategoryForm):
files = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}),required=False)
class Meta(CategoryForm.Meta):
fields = CategoryForm.Meta.fields + ['files']
views.py
####### CATEGORY VIEWS ########
class CategoryListView(LoginRequiredMixin, ListView):
model = Category
template_name = 'ProjectManagementApp/PM-Category-List.html'
context_object_name = 'categories'
slug_field = 'project_slug'
success_url = reverse_lazy('Category-list')
class CategoryDetailView(LoginRequiredMixin, DetailView):
model = Category
template_name = 'ProjectManagementApp/PM-Category-Detail.html'
slug_field = 'category_slug'
def get_context_data(self, **kwargs):
context = super(CategoryDetailView, self).get_context_data(**kwargs)
context['files'] = CategoryFiles.objects.all()
#context['photos'] = CategoryPhotos.objects.all()
return context
class CategoryCreateView(LoginRequiredMixin, CreateView):
model = Category
form_class = CategoryFullForm
template_name = 'ProjectManagementApp/PM-Category-Create.html' # Replace with your template.
#success_url = reverse_lazy('category-detail')
slug_field = 'category_slug'
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('files')
if form.is_valid():
author = request.user
name = form.cleaned_data['name']
est_pr_sqft = form.cleaned_data['est_pr_sqft']
est_duration = form.cleaned_data['est_duration']
preceding_job = form.cleaned_data['preceding_job']
category_notes = form.cleaned_data['category_notes']
category_obj = Category.objects.create(name=name,est_pr_sqft=est_pr_sqft,est_duration=est_duration,preceding_job=preceding_job,category_notes=category_notes,author=author)
for f in files:
CategoryFiles.objects.create(category_id=category_obj,document=f)
return HttpResponseRedirect(reverse_lazy('Category-list'))
else:
return self.form_invalid(form)
class CategoryUpdateView(LoginRequiredMixin, UpdateView): #UserPassesTestMixin - makes sure user who made entry is only one who can update it.
model = Category
form_class = CategoryFullForm
template_name = 'ProjectManagementApp/PM-Category-Create.html' # Replace with your template.
slug_field = 'category_slug'
success_url = reverse_lazy('Category-list')
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('files')
if form.is_valid():
author = request.user
name = form.cleaned_data['name']
est_pr_sqft = form.cleaned_data['est_pr_sqft']
est_duration = form.cleaned_data['est_duration']
preceding_job = form.cleaned_data['preceding_job']
category_notes = form.cleaned_data['category_notes']
category_obj = Category.objects.create(name=name,est_pr_sqft=est_pr_sqft,est_duration=est_duration,preceding_job=preceding_job,category_notes=category_notes,author=author)
for f in files:
CategoryFiles.objects.create(category_id=category_obj,document=f)
return HttpResponseRedirect(reverse_lazy('Category-list'))
else:
return self.form_invalid(form)
#
# #Doesnt allow you to update other users post
# #def test_func(self):
# # project = self.get_object()
# # if self.request.user == post.author:
# # return True
# # return False
#
#
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
class CategoryDeleteView(LoginRequiredMixin, DeleteView): #UserPassesTestMixin - makes sure user who made entry is only one who can update it.
model = Category
template_name = 'ProjectManagementApp/PM-Category-Delete.html'
slug_field = 'category_slug'
success_url = reverse_lazy('Category-list')
#Doesnt allow you to delete other users post
#def test_func(self):
# project = self.get_object()
# if self.request.user == post.author:
# return True
# return False
If the urls.py/admin.py are needed am happy to provide, but don't think they are needed, as well as any of the html files.
I have this django model for questions.
class Question(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, null=True, on_delete=models.SET_NULL)
question_id = models.CharField(max_length=150, null=False, default=get_id, unique=True, editable=False)
question = models.CharField(max_length=150, null=False)
question_description = FroalaField()
created_at = models.DateTimeField(auto_now=False, auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=False)
question_image = models.ImageField(upload_to=get_upload_path, blank=True, null=True)
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
dynamic_link = models.CharField(max_length=225, null=False, default="")
question_type = models.CharField( max_length=50, null=False, choices=QUESTIONSTYPE_LIST)
question_status = models.CharField(max_length=150, null=False, default="unapproved")
is_active = models.BooleanField(default=False)
objects = QuestionManager()
class Meta:
ordering = ['-updated_at']
def __str__(self):
return self.question_id
def get_absolute_url(self):
kwargs = {
'questiontype': slugify(self.question_type),
'questionid': self.question_id,
'slug': slugify(self.question)
}
return reverse("questions:detail", kwargs=kwargs)
Everything seems to be working okay, except that the user user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, null=True, on_delete=models.SET_NULL)
always saves but the default which is 1. So no matter which user is logged in and in session, it always defaults to 1.
I am using classed-based-views and the user is a CustomUser.
I have the customUser set in settings.py auth_model_user as:
AUTH_USER_MODEL = 'users.CustomUser'
Here is the form for Question:
class QuestionCreationUpdateForm(forms.ModelForm):
question = forms.CharField(widget=forms.TextInput(attrs={
'class': 'frm-input',
'placeholder': _('Enter question title'),
'autocomplete': 'off'
}))
question_type = forms.ChoiceField(choices=QUESTIONSTYPE_LIST, widget=forms.Select(attrs={'class': 'frm-input'}))
question_description = forms.CharField(widget=FroalaEditor)
def __init__(self, *args, **kwargs):
super(QuestionCreationUpdateForm, self).__init__(*args, **kwargs)
class Meta:
model = Question
fields = ('question', 'question_description', 'question_type')
And the question CreateView:
# Add Question View
#method_decorator(login_required, name='dispatch')
class AskQuestionView(CreateView):
template_name = 'ask_question.html'
form_class = QuestionCreationUpdateForm
model = Question
def form_valid(self, form):
try:
return super(AskQuestionView, self).form_valid(form)
except IntegrityError:
context = {
'msg': _('We don\'t allow continues posting! Take a break. Try again later!')
}
return render(self.request, "500.html", context)
def get_success_url(self):
return self.object.get_absolute_url()
If I do a request.user in the views.py file, I always get the right user.
So why is my model behaving this odd?
As I can see, you need to assign the User object to form instance. Like this:
#method_decorator(login_required, name='dispatch')
class AskQuestionView(CreateView):
...
def form_valid(self, form):
try:
obj = form.save(commit=False)
obj.user = self.request.user
return super(AskQuestionView, self).form_valid(obj)
except IntegrityError:
context = {
'msg': _('We don\'t allow continues posting! Take a break. Try again later!')
}
return render(self.request, "500.html", context)
# ^^ consider using a 400 error response, as 500 is for server error response. 400 is for bad request
...
You are not assigning any user to Question.user. You need to assign the current user to that field.
#method_decorator(login_required, name='dispatch')
class AskQuestionView(CreateView):
template_name = 'ask_question.html'
form_class = QuestionCreationUpdateForm
model = Question
def form_valid(self, form):
try:
form.instance.user = self.request.user
return super(AskQuestionView, self).form_valid(form)
except IntegrityError:
context = {
'msg': _('We don\'t allow continues posting! Take a break. Try again later!')
}
return render(self.request, "500.html", context)
Further read Models and request.user
I'm using class based views in my project. In CreateView using multiple forms (inlineformset_factory) is working and I saved my both forms data successfully.
But when I tried to edit my formset using using class based views (UpdateView) only first form data is updated successfully.
But the formset (inlineformset_factory) data is not updated.
Please help to find out problem in my (UpdateView).
views.py
class MaterialRequest_update(UpdateView):
template_name = 'inventory/edit_files/material_request.html'
form_class = MaterialRequestForm
model = MaterialRequest
success_url = reverse_lazy('inventory-material-request')
def get_queryset(self):
id = self.kwargs['pk']
return MaterialRequest.objects.filter(pk=id)
def get_context_data(self, **kwargs):
context = super(MaterialRequest_update, self).get_context_data(**kwargs)
if self.request.POST:
context['form'] = MaterialRequestForm(self.request.POST, instance=self.object)
context['formset'] = MaterialRequestFormset(
self.request.POST, instance=self.object)
else:
context['form'] = MaterialRequestForm(instance=self.object)
context['formset'] = MaterialRequestFormset(instance=self.object)
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
if form.is_valid() and formset.is_valid():
form.save()
formset.save()
return super().form_valid(form)
forms.py
# Main Form
class MaterialRequestForm(forms.ModelForm):
class Meta:
model = MaterialRequest
fields = [
'location', 'job', 'task_num', 'supervisor', 'entry_serialno', 'date',
'department', 'ref', 'other_info', 'attachment'
]
labels = {
'location':'Location', 'job':'Job', 'task_num':'Estimate No',
'supervisor':'Supervisor', 'entry_serialno':'Entery No', 'date':'Date',
'department':'Department', 'ref':'Reference', 'other_info':'Other Info',
'attachment':'Attachment File'
}
widgets = {
'location': forms.Select(attrs={'class':'form-control select-search'}),
'job': forms.Select(attrs={'class':'form-control select-search'}),
'task_num': forms.TextInput(attrs={'class':'form-control'}),
'supervisor': forms.TextInput(attrs={'class':'form-control'}),
'entry_serialno': forms.TextInput(attrs={'class':'form-control'}),
'date': forms.DateInput(attrs={'class':'form-control pickadate'}),
'department': forms.Select(attrs={'class':'form-control select-search'}),
'ref': forms.TextInput(attrs={'class':'form-control'}),
'other_info': forms.Textarea(attrs={'class':'form-control', 'rows':3}),
'attachment': forms.ClearableFileInput(attrs={'class':'form-control'})
}
def clean(self):
fields = self.cleaned_data
# Formset start from here
MaterialRequestFormset = inlineformset_factory(
MaterialRequest,
MaterialRequestProducts,
form = MaterialRequestForm,
extra=1,
can_delete=True,
max_num=200,
validate_max=200,
fields=('product', 'quantity', 'unit', 'stock'),
widgets={
'product': forms.Select(attrs={'class':'form-control select-search'}),
'quantity': forms.NumberInput(attrs={'class':'form-control'}),
'unit': forms.Select(attrs={'class':'form-control select-search'}),
'stock': forms.NumberInput(attrs={'class':'form-control'}),
}
)
models.py
class MaterialRequest(models.Model):
location = models.ForeignKey(to='administrator.Location', related_name='materialreq_location', on_delete=models.CASCADE)
job = models.ForeignKey(to='master.Job', related_name='materialreq_job', on_delete=models.CASCADE)
task_num = models.CharField(max_length=100, blank=True)
supervisor = models.CharField(max_length=100, blank=True)
entry_serialno = models.CharField(max_length=100, blank=True)
date = models.CharField(max_length=100, blank=True)
department = models.ForeignKey('master.Department', related_name='department', on_delete=models.CASCADE, null=True)
ref = models.CharField(max_length=100, blank=True)
other_info = models.TextField(blank=True)
attachment = models.FileField(upload_to='files/inventory/material_request/%Y/%m/%d/', null=True, blank=True)
added_by = models.CharField(max_length=200, default='Azhar Saleem')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = models.Manager
def __str__(self):
return self.job
class Meta:
db_table = 'inventory_material_request'
verbose_name = 'Material_Request'
verbose_name_plural = 'Material_Requests'
#Formset model start from here...
class MaterialRequestProducts(models.Model):
material_request = models.ForeignKey(MaterialRequest, related_name='materialrequest', on_delete=models.CASCADE)
product = models.ForeignKey(Products, related_name='products', on_delete=models.CASCADE)
quantity = models.BigIntegerField()
unit = models.ForeignKey('master.UnitOfMeasurements', related_name='unit', on_delete=models.CASCADE)
stock = models.DecimalField(max_digits=999, decimal_places=2)
add_by = models.CharField(max_length=100, default='Azhar Saleem')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = models.Manager
def __str__(self):
return self.product
class Meta:
db_table = 'inventory_material_request_products'
verbose_name = 'Material_Request_Product'
verbose_name_plural = 'Material_Request_Products'
Try this.
class MaterialRequest_update(UpdateView):
model = MaterialRequest
form_class = MaterialRequestForm
template_name = 'inventory/edit_files/material_request.html'
slug_field = 'uid'
slug_url_kwarg = 'uuid'
success_message = 'Data saved successfully'
def get_success_url(self):
return reverse_lazy('inventory-material-request')
def get_context_data(self, **kwargs):
context = super(MaterialRequest_update, self).get_context_data(**kwargs)
if self.request.POST:
context['form'] = MaterialRequestForm(self.request.POST, instance=self.object)
context['formset'] = MaterialRequestFormset(self.request.POST,
instance=self.object)
else:
context['form'] = MaterialRequestForm(instance=self.object)
context['formset'] = MaterialRequestFormset(instance=self.object)
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = MaterialRequestFormset(self.request.POST, instance=self.object)
if (form.is_valid() and formset.is_valid()):
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
self.object = form.save()
formset.instance = self.object
formset.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, formset):
return self.render_to_response(self.get_context_data(form=form, formset=formset))
I just want to filter select field in a form, regarding a currently logged user. Every user has own categories and budgets - I want to display only a models related with a currently logged user. I've tried stuff with filtering before is_valid field, but with no result. Please, find my code below:
views.py
#login_required
def day_data_multiadd(request, no_of_lines=0):
no_of_lines = int(no_of_lines)
CostFormSet = modelformset_factory(Cost, form=DataAddForm, extra=no_of_lines)
if request.method == 'POST' and 'form' in request.POST:
formset = CostFormSet(request.POST, request.FILES)
if formset.is_valid():
for form in formset.forms:
f = form.save(commit=False)
f.user = request.user
f.save()
else:
formset = CostFormSet(queryset=Cost.objects.none())
if request.method == 'POST' and 'no_line' in request.POST:
generate_form = MultiaddGenerateForm(request.POST)
if generate_form.is_valid():
cd = generate_form.cleaned_data
return HttpResponseRedirect(reverse('core_sm:day_data_multiadd', args=(cd['formy'], )))
else:
generate_form = MultiaddGenerateForm()
return render(request, 'core_sm/costs/multi_add.html', {'formset': formset,
'no_of_lines': no_of_lines,
'generate_form': generate_form})
forms.py
class DataAddForm(forms.ModelForm):
class Meta:
model = Cost
fields = ['title', 'value', 'publish', 'category', 'budget']
exclude = ['user']
labels = {
'title': _('Tytuł'),
'value': _('Wartość'),
'publish': _('Data'),
'category': _('Kategoria'),
'budget': _('Budżet')
}
models.py
class Category(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200)
publish = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_ur(self):
return reverse('core_sm:category_detail', args=[self.id])
class Budget(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200, db_index=True)
value = models.DecimalField(decimal_places=2, max_digits=10)
publish = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('core_sm:budget_detail', args=[self.id])
class Cost(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
budget = models.ForeignKey(Budget, related_name='cost')
category = models.ForeignKey(Category, related_name='cost')
title = models.CharField(max_length=200, db_index=True)
publish = models.DateField(default=timezone.now)
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
value = models.DecimalField(max_digits=10, decimal_places=2)
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('core_sm:stats_detail', args=[self.publish.year,
self.publish.strftime('%y'),
self.publish.strftime('%m'),
self.publish.strftime('%d')])
def __str__(self):
return self.title
According to the docs you can pass custom parameters to formsets forms.
class DataAddForm(forms.ModelForm):
class Meta:
model = Cost
fields = ['title', 'value', 'publish', 'category', 'budget']
exclude = ['user']
labels = {
'title': _('Tytuł'),
'value': _('Wartość'),
'publish': _('Data'),
'category': _('Kategoria'),
'budget': _('Budżet')
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
self.fields['category'].queryset = Category.objects.filter(user=user)
self.fields['budget'].queryset = Budget.objects.filter(user=user)
super(DataAddForm, self).__init__(*args, **kwargs)
views.py
formset = CostFormSet(queryset=Cost.objects.none(), form_kwargs={'user': request.user})