How to populate django form with selection from your models - django

I have a CreateSong CBV in Django that allows me to create song objects to a model. My question is, in the form I created for the view, how do I make the album column to be auto-populated with albums the user-created only? I get errors calling "self" that way.
See my views below
class CreateSong(CreateView):
model = Song
fields = [album, song_title]
fields['album'].queryset = Album.objects.filter(owner=self.request.user)

I think you should override get_form. See the example below:
class CreateSong(CreateView):
model = Song
fields = [album, song_title]
def get_form(self):
form = super().get_form()
form.fields['album'].queryset = Album.objects.filter(owner=self.request.user)
return form

You do not have access to self.request.user, because you are calling it at class level, thus when the class is being defined and not when the view is actually called. Instead you should override the get_form method as in Davit's answer.

Related

Class Based Views UpdateView django different type of model

how can I change model in UpdateView for different type of users? I have Student and Teacher inherited from AbstractBaseUser, and I need edit for for them
class EditUser(UpdateView):
success_url = '/success/'
template_name = 'edit-profile.html'
model = Teacher (I need to choose this Teacher or Student)
I know about get_template_names(self) method or get_success_url(self), but can not find any get_model method.
I need somethng like:
def get_model_name(self):
if self.request.user.user_type == 'teacher':
return Teacher
if self.request.user.user_type == 'student':
return Studend
Thank you.
According to Django documentation:
model
The model that this view will display data for. Specifying model = Foo
is effectively the same as specifying queryset = Foo.objects.all(),
where objects stands for Foo’s default manager.
queryset
A QuerySet that represents the objects. If provided, the value of
queryset supersedes the value provided for model.
get_queryset()
Returns the queryset that will be used to retrieve the object that
this view will display. By default, get_queryset() returns the value
of the queryset attribute if it is set, otherwise it constructs a
QuerySet by calling the all() method on the model attribute’s default
manager.
So, all you need is redefine get_queryset method

WTForm with more than one model object

I have a page that should create an instance of two distinct models at the same time, ie, when the same form is submitted.
I created a form using wtforms_alchemy but this covers only one model, not both:
class RoutineForm(ModelForm):
class Meta:
model = Routine
only = [u'name', u'comment']
field_args = {u'comment': {'widget': TextArea()}, }
I know I could create a form that does not inherit from the model and includes all the fields I need but for the sake of keeping things DRY how can I have an instance of ModelForm use two models?
You can use multiple forms at the same time. Give each a prefix to make sure the field names don't overlap in HTML. Validate both forms. Other than having two form objects, everything else is normal about the view and template.
class RoutineForm(ModelForm):
...
class EventForm(ModelForm):
...
#app.route('/make_event', methods=['GET', 'POST'])
def make_event():
routine_form = RoutineForm(prefix='routine')
event_form = EventForm(prefix='event')
if request.method == 'POST' and routine_form.validate() and event_form.validate():
...
return render_template('make_event.html', routine_form=routine_form, event_form=event_form)

Django forms and querysets

Lets say I need to filter the options available in a multiple select box.
in my view I have:
class ArticleCheckbox(forms.ModelForm):
article= forms.ModelMultipleChoiceField(queryset=Article.objects.all(),required=False, widget=forms.CheckboxSelectMultiple)
class Meta:
model = Book
fields = ('m2m_article',)
.
In my view I will assign:
articleform = ArticleCheckbox()
articleform.fields["m2m_article"].queryset = Article.objects.filter(category = "Animals")
How does the assigning of the queryset in the view affect the queryset from classes (Article.object.all()) ?
Does it overwrite? I do not think so.
I would like to override the queryset. How can I do it?
Does this work?
article=forms.ModelMultipleChoiceField(queryset=Article.objects.all().filter(category = "Animals"),required=False, widget=forms.CheckboxSelectMultiple)
Directly in the model. Or do you want to leave the filtering to the view to do different things?
The way you're doing it is correct, except for you assign the class and not an instance of ArticleCheckBox
articleform = ArticleCheckbox()
When the form is initialised it is given a default queryset and you are overriding it, the initial one will never query the database since no data is ever needed to be retrieved at that point.

Edit related object using ModelFormSet

I was using a model formset to generate a table of forms for a list of objects.
Forms:
class UserTypeModelForm(ModelForm):
account_type = ChoiceField(label='User type',
choices=ACCOUNT_OPTIONS, required=False)
class Meta:
model = get_user_model()
fields = ('account_type',)
UserTypeModelFormSet = modelformset_factory(get_user_model(),
form=UserTypeModelForm,
extra=0)
View:
formset = UserTypeModelFormSet(queryset=users, prefix='formset')
Now my client wants to be able to modify a related field: user.employee_profile.visible.
I tryed to add a field to the form, and then passing "initial" and "queryset" to the formset, but It looks like it just takes one.
How would you guys do this?
Thanks
with model formsets, the initial values only apply to extra forms, those that aren’t bound to an existing object instance.
Django docs
The queryset provides the selected/entered values for the bound fields, the initial for the extra fields (in your case 0).
But you can override the initial value in e.g. your views when you created a field called employee in this case:
for form in forms:
# Don't override a selected value.
if not form.fields['employee'].initial:
form.fields['employee'].initial = my_init

UpdateView - Update a class that has OneToOne with User

Say I have a model called MyUser. It has some field, and one of them is this one:
user = OneToOneField(User, related_name='more_user_information')
I want to make a view to update this model, and I do the following:
Class AccountEdit(LoginRequiredMixin, UpdateView):
model = MyUser
form_class = MyUserForm
template_name = 'accounts/edit.html'
def get_object(self, queryset=None):
return self.model.objects.get(user=self.request.user)
Each field in MyUser renders fine for editing, except user. This one to one field becomse a select drop down box. What I like to do is to edit the fields on User model like first name or last name.
How can I achieve this while extending UpdateView? or perhaps shuold I use a FormView?
thanks
This problem is actually nothing to do with class based views or update view - its a basic issue that has been there since the beginning, which is:
ModelForms only edit the fields for one model, and don't recurse into
foreign keys.
In other words, if you have a model like this:
class MyModel(models.Model):
a = models.ForeignKey('Foo')
b = models.ForeignKey('Bar')
c = models.ForeignKey('Zoo')
name = models.CharField(max_length=200)
A model form will render three select fields, one for each foreign key, and these select fields will have all the values from those models listed - along with one text field for the name.
To solve this problem, you need to use InlineFormSets:
Inline formsets is a small abstraction layer on top of model formsets.
These simplify the case of working with related objects via a foreign
key.
You should use InlineFormSet from the excellent django-extra-views app. To do this, you'll create a view for the related object as well:
class MyUserInline(InlineFormSet):
model = MyUser
def get_object(self):
return MyUser.objects.get(user=self.request.user)
class AccountEditView(UpdateWithInlinesView):
model = User
inlines = [MyUserInline]
Another option is django-betterforms's Multiform and ModelMultiForm.
Example:
class UserProfileMultiForm(MultiForm):
form_classes = {
'user': UserForm,
'profile': ProfileForm,
}
It works with generic CBV (CreateView, UpdateView, WizardView).