Django ClassBasedViews - Generic Views - django

I get a strange Error: 'ListView' must define 'queryset' or 'model'
Here is my ListView:
class ProjectListView(ListView):
template_name = "ProjectList.html"
model = Project
context_object_name = "projects"
I have the same problem with a CreateView. Is there any other information need to find a solution?
How to fix this error.

You must define a get_queryset() function in each generic ListView view.
That's how you tell django what objects you want to display.
Model is NOT your project. It must be set to a model class.
Say, you have a model called Poll in your models.py file. And you want to display all polls in the db, using the generic ListView. Then you could write this:
model = Poll
That equals to this query:
Poll.objects.all()
If you want to override this and show objects e.g. with publication date during the last week, then you define a get_queryset() with nedeed query parameters:
ProjectListView(generic.ListView):
# ...
def get_queryset(self):
return obj.objects.filter(pub_date__gte=timezone.now() - datetime.timedelta(days=7))
And so on.

Related

How to populate django form with selection from your models

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.

Django - force pk_url_kwarg to query other model instances

Consider the following code:
views.py
class BHA_UpdateView(UpdateView):
model = BHA_overall
pk_url_kwarg = 'pk_alt'
form_class = BHA_overall_Form
To my understanding, pk_url_kwarg = 'pk_alt' will query and return instances of model = BHA_overall.
Is there any way that I can force pk_url_kwarg to query
& return other model instances defined in models.py (like model = other_model), while having my get_object() method to return objects in model = BHA_overall? What CBV should I use (I think UpdateView is not a good choice in this case)?
++ I'm trying to make a page that allows users to manage information about the product they use. So, ultimately I will implement forms, and the user input needs to be saved in DB
++ I need pk_url_kwarg = 'pk_alt' to query other models and generate url. But I still need get_object() method to return objects in model = BHA_overall to generate form fields on the user side.
From my understanding you need a django form generated from BHA_overall, but the data should be saved to AnotherModel right?
I will propose 2 solutions to this problem, Choose what best fits you.
Multiple views:
Have multiple views for the task, What I mean is create a view which creates the form for the frontend using BHA_overall, you can create both Create and Update view this way and update view's initial could be overwritten so form will have expected value when editing. And now post the data to another view which handles the post data. This view can have your AnotherModel doing its thing.
Using Django Form:
If you dont like having multiple views, You can keep things simple by creating a form yourself. Create a DjangoForm with the same fields you want to show to the user and use it in to create your own views, Now you wont need BHA_overall and use your AnotherModel to save datal.

How to get user specific object using django generic class detailview?

How do I get the current user related object using django's generic class DetailView? Using function based views, I can obtain the object like this:
def foo(request):
friendProfile = get_object_or_404(request.user.profile.friends,username="admin")
What is the equivalent using detail view? I'm guessing it's something related to get_object or get_context_data but I can't fully understand the documents.
Thank you.
request is an attribute of class based views. To get the current user you should use self.request.user.
On a DetailView overload the get_queryset to edit the queryset used to get the object.
I don't know precisely how your friend model is defined but let's assume it has a foreign key pointing to your profile with a related_name set to friend_of. Your view could be:
class FriendProfileDetail(DetailView):
model = Friend
def get_queryset(self):
return self.model.objects.filter(friend_of=self.request.user.profile)

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

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).