ModelForm object has no attribute 'fields' - django

I am using a django (3.0) ModelMultipleChoice field for a form. I am trying to modify the queryset to make some restrictions on it.
here is the views :
def nouvelle_tache(request,id_livrable):
livrable=Livrable.objects.get(pk=id_livrable)
projet = livrable.projet
if request.method == "POST":
form = NouvelleTache(request.POST,projet=projet)
tache = form.save(commit=False)
tache.livrable = livrable
tache.id_tache = livrable.id_derniere_tache() + Decimal(0.01)
tache.save()
form.save_m2m()
etat = Temps_etat_tache(etat=form.cleaned_data['etat_initial'],tache=tache)
etat.save()
return redirect('tache',tache.pk)
else:
form = NouvelleTache(projet=projet)
return render(request, 'application_gestion_projets_AMVALOR/nouvelle_tache.html', locals())
And the forms :
class NouvelleTache(forms.ModelForm):
def __init__(self, *args, **kwargs):
projet = kwargs.pop('projet', None)
queryset = Utilisateur.objects.all()
for utilisateur in projet.utilisateurs:
queryset = queryset.exclude(pk=utilisateur.pk)
self.fields['ressources'].queryset = queryset
super(NouvelleTache, self).__init__(*args, **kwargs)
ressources= forms.ModelMultipleChoiceField(queryset=Utilisateur.objects.all() ,widget =forms.CheckboxSelectMultiple )
etat_initial = forms.ModelChoiceField(queryset=Etat_tache.objects.none())
class Meta:
model = Tache
fields = ['libelle']
I have the followig error : 'NouvelleTache' object has no attribute 'fields'
I don't understand why because many other users seems to have similar code and it works.
Any help would be appreciate.

super(NouvelleTache, self).__init__(*args, **kwargs)
needs to be executed first, as the fields are set in the super class:
def __init__(self, *args, **kwargs):
projet = kwargs.pop('projet', None)
queryset = Utilisateur.objects.all()
for utilisateur in projet.utilisateurs:
queryset = queryset.exclude(pk=utilisateur.pk)
super(NouvelleTache, self).__init__(*args, **kwargs)
self.fields['ressources'].queryset = queryset

Related

How to use the same ModelForm form different admin classes with different models

I'm trying to create a common form with a date range validation that will be used in 20 admin classes with different model
So I'm creating this mixin for each of them to use
class DateControllerMixin():
def get_queryset(self, request):
qs = dateControlQuerySet(super().get_queryset(request), self.parameter_name, request)
return qs
def get_form(self, request, obj=None, change= None,**kwargs):
print(self.parameter_name)
if request.user.groups.filter(name='slaughterhouse_date_controlled').exists():
form = DateControlledForm
form.model_class = self.model
form.parameter_name = self.parameter_name
return form
return super().get_form(request, obj, change, **kwargs)
And this is the form but I can't find a way to make the form without specifying the model class in the Meta or use class attributes
class DateControlledForm(forms.ModelForm):
def __init__(
self, *args, **kwargs
):
self._meta.model = self.model_class
super(DateControlledForm, self).__init__(*args, **kwargs)
class Meta:
# model = self.model_class
fields='__all__'
widgets = {
'the_date': AdminDateWidget(),
}
def clean(self, **kwargs):
print(self.paramter_name)
date = self.cleaned_data.get('the_date')
today = datetime.today().date()
days_limit = AppConfigurations.objects.get(parameter_name=self.parameter_name).parameter_value
first_day = today - timedelta(days = int(days_limit))
if date < first_day:
raise forms.ValidationError({
'the_date': [_(f"Date cannot be before {first_day}.")]})
return self.cleaned_data
I tried to edit the meta options from the init method but it didn't work

Django, how to set value in forms.ModelForm

I have a question for you. I have the following Model:
class Centro_di_costo(models.Model):
centro_di_costo = models.CharField('Centro di costo', max_length=30)
def __str__(self):
return self.centro_di_costo
class AltriCosti(models.Model):
STATUS_CHOICES= [
('VARIABILE', 'VARIABILE'),
('FISSO', 'FISSO'),
]
centro_di_costo = models.ForeignKey(Centro_di_costo)
sub_centro_di_costo = models.CharField('Categoria', max_length=30)
status = models.CharField(choices=STATUS_CHOICES)
price=models.DecimalField()
quantity=models.IntegerField()
I use it in a lot of view, but in one of them I wanna set the value without passing from the POST request.
So I have tried to set the ModelForm in the following manner:
class ModCollaboratori(forms.ModelForm):
class Meta:
model = AltriCosti
fields = "__all__"
def __init__(self, *args, **kwargs):
super(ModCollaboratori, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
self.fields['centro_di_costo'].value= "Servizi di Produzione"
self.fields['sub_centro_di_costo'].value = "Collaboratori esterni"
self.fields['status'].value = "VARIABILE"
But It does not work. How could I fix the code to work?
You can exclude fields from your form:
class ModCollaboratori(forms.ModelForm):
class Meta:
model = AltriCosti
exclude = ['centro_di_costo', 'sub_centro_di_costo', 'status']
Then in your view you can "inject" value for these fields:
def some_view(request):
if request.method == 'POST':
form = ModCollaboratori(request.POST, request.FILES)
if form.is_valid():
form.instance.sub_centro_di_costo = 'Collaboratori esterni'
form.instance.status = 'VARIABILE'
form.instance.centro_di_costo = Centro_di_costo.objects.get_or_create(
centro_di_costo='Servizi di Produzione'
)[0]
form.save()
return redirect('name-of-some-view')
else:
form = ModCollaboratori()
return render(request, 'some_template.html', {'form': form})
for your code
self.fields['status'].value = "VARIABLE"
to make it work change to
self.instance.status = "VARIABLE"
Result:
Status: VARIABLE
basically ModelForm.__init__() will populate instance values into form.
but if we add extra field to this form, we will need to populate it by ourself in kwargs["initial"],
because this field not include in the model.
class SomeForm(forms.ModelForm):
custom_field = forms.CharField()
def __init__(self, *args, **kwargs):
kwargs["initial"]["custom_field"] = "xxxxx"
super().__init__(*args, **kwargs)

how to get url parameter in modelform

I have one model name is cityform
i want to get url parmeter in this CityFrom hwo can i do this?
here is my url
path('state/city/<int:id>/', City.as_view(), name="city")
http://localhost:8000/country/state/city/3/
here is my form
class
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CityFrom,self).__init__(*args, **kwargs)
print(args)
print(kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
in this form i want to access id = 3
here is my view
from django.views import View
class City(View):
def get(self, request, *args, **kwargs):
Forms = CityFrom()
return render(request, 'albums/add.html', {'Forms': Forms})
Pass url parameter as keyword argument from views.py as following.
form = CityFrom(id=kwargs.get("id"))
To get the id in your forms.py, use following code in your form's __init__ method.
self.id = kwargs.get('id')
Your form should look like this.
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.get('id')
super(CityFrom,self).__init__(*args, **kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
* Call super after getting the id in your form as above. Here order of calling super is important.
Try
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.pop('id')
super(CityFrom,self).__init__(*args, **kwargs)

How to perform queries in django modelform?

I tried this in my modelform:
class Ledgerform(forms.ModelForm):
class Meta:
model = ledger1
fields = ('name', 'group1_Name')
def __init__(self, User, Company, *args, **kwargs):
self.User = kwargs.pop('User', None)
self.Company = kwargs.pop('Company', None)
super(Ledgerform, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs = {'class': 'form-control',}
self.fields['group1_Name'].queryset = group1.objects.filter(User= self.User,Company = self.Company)
In my views.py I have done something like this:
class ledger1ListView(LoginRequiredMixin,ListView):
model = ledger1
paginate_by = 15
def get_queryset(self):
return ledger1.objects.filter(User=self.request.user, Company=self.kwargs['pk'])
class ledger1CreateView(LoginRequiredMixin,CreateView):
form_class = Ledgerform
def form_valid(self, form):
form.instance.User = self.request.user
c = company.objects.get(pk=self.kwargs['pk'])
form.instance.Company = c
return super(ledger1CreateView, self).form_valid(form)
I want to perform the the same query that I have passed in my ledger1ListView by using queryset in my modelform but my kwargs.pop is not returning the current user or the company...
This is my models.py:
class ledger1(models.Model):
User = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,null=True,blank=True)
Company = models.ForeignKey(company,on_delete=models.CASCADE,null=True,blank=True,related_name='Companys')
name = models.CharField(max_length=32)
group1_Name = models.ForeignKey(group1,on_delete=models.CASCADE,blank=True,null=True)
Do any one know what I am doing wrong in my code?
Thank you in advance
You can override the FormMixin.get_form_kwargs [Django-doc] in your view, that it constructs a dictionary with the parameters necessary to initialize the form, like:
class ledger1CreateView(LoginRequiredMixin,CreateView):
form_class = Ledgerform
def get_form_kwargs(self):
data = super(ledger1CreateView, self).get_form_kwargs()
data.update(
User=self.request.User,
Company=company.objects.get(pk=self.kwargs['pk'])
)
return data
The form_valid function is called after the form is constructed, validated and appears to be valid. Typically it is used to redirect the user to the "success page".

Django ModelForm with field overwrite does not post data

So, I have the following form:
class DesignItemForm (forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DesignItemForm, self).__init__(*args, **kwargs)
CHOICES=[(i,i) for i in range(MAX_DESIGN_ITEM_QUANTITY)]
self.fields['quantity'] = forms.ChoiceField(choices=CHOICES)
class Meta:
model = DesignItem
fields = ('quantity','trackable',)
My view:
d = Design.object.get(slug=fromInput)
....
DesignItemInlineFormSet = inlineformset_factory(Design, DesignItem, fk_name="design", form=DesignItemForm,)
if request.method == "POST":
formset = DesignItemInlineFormSet(request.POST, request.FILES, instance=d)
if formset.is_valid():
formset.save()
DesignItemInlineFormSet(instance=d)
As you can tell, in my form, I overwrote the quantity field to be a drop down instead of an integer field.
For some reason, when I submit the form, the data is not updated in the database. However, if I change the form to the following, it works (of course, it doesn't have the dropdowns I want, but it posts to the db). Why is this, and how do I fix it?
class DesignItemForm (forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DesignItemForm, self).__init__(*args, **kwargs)
# CHOICES=[(i,i) for i in range(MAX_DESIGN_ITEM_QUANTITY)]
# self.fields['quantity'] = forms.ChoiceField(choices=CHOICES)
class Meta:
model = DesignItem
fields = ('quantity','trackable',)
EDIT: Here is the DesignItem model:
class DesignItem(models.Model):
"""Specifies how many of an item are in a design."""
design = models.ForeignKey(Design, related_name="items")
quantity = models.PositiveIntegerField(default=1)
trackable = models.ForeignKey(Trackable, related_name="used")
have you tried just overriding the widget instead of the whole field?
i guess you want a select widget
def __init__(self, *args, **kwargs):
super(DesignItemForm, self).__init__(*args, **kwargs)
CHOICES=[(i,i) for i in range(MAX_DESIGN_ITEM_QUANTITY)]
self.fields['quantity'].widget = forms.Select(choices=CHOICES)