Django, how to set value in forms.ModelForm - django

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)

Related

ModelForm object has no attribute 'fields'

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

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: Save id on a OneToOneField

models:
class UserDataUpdate(models.Model):
code = models.CharField(max_length=8)
address = models.CharField(max_length=50)
class UserSurvey(models.Model):
about_treatment = models.CharField(max_length=2)
user_data_update = OneToOneField(UserDataUpdate)
views:
#login_required
def generate_survey(request):
user_data_update = UserDataUpdate.objects.get(code=request.user.username)
if request.method == 'POST':
form = SurveyForm(request.POST)
if form.is_valid():
form.save()
return redirect('/success')
else:
form = SurveyForm(request.GET)
return render_to_response(
'survey.html',
{'form': form },
context_instance = RequestContext(request))
form:
class SurveyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SurveyForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget = RadioSelect(choices=SURVEY_CHOICES)
class Meta:
model = Survey
exclude = ['user_data_update']
I just need a way to set the UserDataUpdate id (that already has been created) on a UserSurvey.
I'm getting this message on generate_survey request.POST:
user_data_update_app_usersurvey.user_data_update_id may not be NULL
It should be clear to you that you get the user_data_update value but then don't do anything with it. I guess you want to set it on the object that's created by the form:
if form.is_valid():
instance = form.save(commit=False)
instance.user_data_update = user_data_update
instance.save()
(I don't understand what all that stuff in the form's __init__ method is supposed to do. You only have one field in your form, anyway.)

django form set current login user

#login_required
def post_review(request):
if request.method == 'POST':
formset = ReviewForm(request.POST)
if formset.is_valid():
formset.save(commit=False)
#formset.author = User.objects.get(pk=int(request.user.id))
formset.pub_date = datetime.datetime.now
formset.save()
return HttpResponseRedirect(reverse(review_index))
else:
formset = ReviewForm()
return render_to_response("review/post_review.html",
{"formset": formset}, context_instance=RequestContext(request),
)
I have this view, I want to auto set the current logged-in user in my review form author field. But I dont know how. Any ideas/hint pls?
Below is my form:
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ('title','category', 'body', )
widgets = {
'body': Textarea(attrs={'cols': 60, 'rows': 20}),
}
I've always done this by accepting a new kwarg in my form's __init__, and saving the value until save-time.
class ReviewForm(ModelForm):
class Meta:
model = Review
fields = ('title','category', 'body', )
widgets = {
'body': Textarea(attrs={'cols': 60, 'rows': 20}),
}
def __init__(self, *args, **kwargs):
self._user = kwargs.pop('user')
super(ReviewForm, self).__init__(*args, **kwargs)
def save(self, commit=True):
inst = super(ReviewForm, self).save(commit=False)
inst.author = self._user
if commit:
inst.save()
self.save_m2m()
return inst
And then in my view:
def post_review(request):
# ... snip ...
if request.method == 'POST'
form = ReviewForm(request.POST, user=request.user)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/') #or whatever the url
else:
# Don't forget to add user argument
form = ReviewForm(user=request.user)
# ... snip ...
If Review.author isn't a required field, you can add a second value to the kwargs.pop call to set a default, like None. Otherwise, if the user kwarg isn't provided, it'll raise an error, effectively making it a required argument.
As an alternative solution, in Django 2+ using a form view - such as a CreateView or FormView, I can simply pass the self.request.user to my pre-saved form model:
class AppCreateView(CreateView):
model = models.App
fields = ['name']
success_url = '/thanks/'
def form_valid(self, form):
app_model = form.save(commit=False)
app_model.author = self.request.user
# app_model.user = User.objects.get(user=self.request.user) # Or explicit model
app_model.save()
return super().form_valid(form)
I agree the class based view is not important here. The important line is app_model.author = self.request.user.
The model is not special:
from django.db import models
from django.contrib.auth.models import User
class App(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=255, help_text="Arbitrary name")
created = models.DateTimeField(auto_now_add=True, max_length=255)
I have a formset mixin which lets you pass extra arguments to the generated forms.
Just add the mixin as the first base class, set a dictionary named "form_kwargs" as a class attribute to describe the
arguments to pass.
from django.forms.formsets import BaseFormSet
class BaseKwargsFormSet(BaseFormSet):
"""
A formset mix-in to allow keyword arguments to be passed to constructed forms
For model_formsets, derive from this model *first* because django's formsets
can't grok the extra arguments.
To use, specify a dictionary with the kwargs & default values as an attribute
named "form_kwargs" on the formset base class.
example:
class BaseUserModelFormset (BaseKwargsFormSet, BaseModelFormSet):
form_kwargs = { 'user': None }
UserFormset = modelformset_factory (usermodel, form=userform,
formset=BaseUserModelFormset)
formset = UserFormset (request.POST or None, user=request.user)
"""
def __init__(self, *args, **kwargs):
form_kwargs = getattr(self, 'form_kwargs', {})
self.form_kwargs = dict((k, kwargs.pop(k, v)) for k, v in form_kwargs.items())
super(BaseKwargsFormSet, self).__init__(*args, **kwargs)
def _construct_form(self, index, **kwargs):
kwargs.update(**self.form_kwargs)
return super(BaseKwargsFormSet, self)._construct_form(index, **kwargs)

Django how to save a custom formset

I've written the following custom formset, but for the life of me I don't know how to save the form. I've searched the Django docs and done extensive searches, but no one solution works. Lots of rabbit holes, but no meat ;-) Can someone point me in the right direction?
// views.py partial //
#login_required
def add_stats(request, group_slug, team_id, game_id, template_name = 'games/stats_add_form.html'):
if request.POST:
formset = AddStatsFormSet(group_slug=group_slug, team_id=team_id, game_id=game_id, data=request.POST)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(reverse('games_game_list'))
else:
formset = TeamStatFormSet(group_slug=group_slug, team_id=team_id, game_id=game_id)
return render_to_response(template_name, {'formset': formset,})
// modles.py partial //
class PlayerStat(models.Model):
game = models.ForeignKey(Game, verbose_name=_(u'sport event'),)
player = models.ForeignKey(Player, verbose_name=_(u'player'),)
stat = models.ForeignKey(Stat, verbose_name=_(u'statistic'),)
total = models.CharField(_(u'total'), max_length=25, blank=True, null=True)
class Meta:
verbose_name = _('player stat')
verbose_name_plural = _('player stats')
db_table = 'dfusion_playerstats'
def __unicode__(self):
return u'%s' % self.player
// forms.py
class TeamStatForm(forms.Form):
total = forms.IntegerField()
class BaseTeamStatsFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
self.group_slug = kwargs['group_slug']
self.team_id = kwargs['team_id']
self.game_id = kwargs['game_id']
self.extra = len(Stat.objects.filter(group__slug=self.group_slug))
del kwargs['group_slug']
del kwargs['game_id']
del kwargs['team_id']
super(BaseTeamStatsFormSet, self).__init__(*args, **kwargs)
def add_fields(self, form, index):
super(BaseTeamStatsFormSet, self).add_fields(form, index)
form.fields["stat"] = forms.ModelChoiceField(queryset = Stat.objects.filter(group__slug=self.group_slug))
form.fields["game"] = forms.ModelChoiceField(queryset = Game.objects.all())
form.fields["team"] = forms.ModelChoiceField(queryset = Team.objects.all())
form.fields["game"].initial = self.game_id
form.fields["team"].initial = self.team_id
TeamStatFormSet = formset_factory(TeamStatForm, BaseTeamStatsFormSet)
In your custom forms, you'll need to add a save() method that stuffs the form data into your models as needed. All of the data entered in the form will be available in a hash called cleaned_data[].
For example:
def save(self):
teamStat = TeamStat(game_id=self.cleaned_data['game_id'],team_id=self.cleaned_data['team_id'])
teamStat.save()
return teamStat
Only model forms and formsets come with a save() method. Regular forms aren't attached to models, so you have to store the data yourself. How to save a formset? from the Django mailing list has an example of saving data from a regular formset.
Edit: You can always add a save() method to a regular form or formset as gbc suggests. They just don't have one built-in.
I don't see a TeamStat model in your code snippets, but if you had one, your forms.py should look something like this:
class TeamStatForm(forms.ModelForm):
total = forms.IntegerField()
class Meta:
model = TeamStat
class BaseTeamStatsFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
self.group_slug = kwargs['group_slug']
self.team_id = kwargs['team_id']
self.game_id = kwargs['game_id']
self.extra = len(Stat.objects.filter(group__slug=self.group_slug))
del kwargs['group_slug']
del kwargs['game_id']
del kwargs['team_id']
super(BaseTeamStatsFormSet, self).__init__(*args, **kwargs)
def add_fields(self, form, index):
super(BaseTeamStatsFormSet, self).add_fields(form, index)
form.fields["stat"] = forms.ModelChoiceField(queryset = Stat.objects.filter(group__slug=self.group_slug))
form.fields["game"] = forms.ModelChoiceField(queryset = Game.objects.all())
form.fields["team"] = forms.ModelChoiceField(queryset = Team.objects.all())
form.fields["game"].initial = self.game_id
form.fields["team"].initial = self.team_id
TeamStatFormSet = modelformset_factory(TeamStatForm, BaseTeamStatsFormSet)
See Creating forms from models from the Django docs