Django - Filtering Field In DetailView - django

Hi all,
I've been building a Django app that allows users to stream and download music. However, there is one issue that I'm having with the artists profile pages; I'm trying to request the songs by the artist only in a DetailView as I'm treating it like a blog system.
Is this possible in a DetailView? Or do I need to make a filter? I've been searching the web for days now and didn't really understand what I can do or how to get the specific data field from the model.
Any help or guidance would be highly appreciated!
class musicartist(DetailView):
model = MusicArtist
template_name = 'RS_MUSIC/artist.html'
# override context data
def get_context_data(self, *args, **kwargs):
context = super(musicartist, self).get_context_data(*args, **kwargs)
# add extra field
current_band = MusicItems.objects.all().filter(artist=MusicArtist.title)[:1]
context["songs"] = MusicItems.objects.filter(artist=MusicArtist.objects.all().filter(title=current_band)[:1])
return context

Managed to figure it out. Just needed the following code:
class musicartist(DetailView):
model = MusicArtist
template_name = 'RS_MUSIC/artist.html'
def get_context_data(self, **kwargs):
context = super(musicartist, self).get_context_data(**kwargs)
context_related = MusicItems.objects.filter(artist=self.object.title)
context['related'] = context_related
return context

Related

Filter model based of context data using django filter

I have a detail view of a model that I want to display together with a list of products and Im trying to integrate django_filter within this view.
Error Message
TypeError at /collections/christmas/?category=mens,
get context data takes exactly 2 arguments (1 given)
Filter
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['categories']
Detail View
class collection_detail(DetailView):
model = Collection
def get_context_data(self, request, **kwargs):
context = super(collection_detail, self).get_context_data(**kwargs)
context['collection_list'] = ProductFilter(request.GET, queryset=Product.objects.filter(collection=self.object.id).filter(structure='parent'))
return context
How i intend it to work
The category filter is pre-defined in a list of links, so when the user clicks on a collection related to a specific category the url of the detail view would look like /collections/christmas/?category=mens .
What am I specifically doing wrong here? Is it possible to even do this?
You're missing *args in your overridden method.
class collection_detail(DetailView):
model = Collection
def get_context_data(self, *args, **kwargs):
context = super(collection_detail, self).get_context_data(*args, **kwargs)
context['collection_list'] = ProductFilter(self.request.GET, queryset=Product.objects.filter(collection=self.object.id).filter(structure='parent'))
return context

Django form text field prefilling with data from other form

I'm running into a very strange issue where one form is initializing with the data from another form entirely. Here is the first view:
class UpdateProfileView(FormMixin, DetailView):
form_class = UpdateProfileForm
model = Profile
template_name = 'profile/update.html'
def get_context_data(self, **kwargs):
self.object = self.get_object()
context = super(UpdateProfileView, self).get_context_data(**kwargs)
...
self.initial['description'] = profile.about
context['form'] = self.get_form()
return context
...
This is the form that will return the correct data. As soon as it is loaded, however, the following form will return the initialized data from the previous one, even from different sessions, browsers, and locations:
class BountyUpdateForm(forms.ModelForm):
class Meta:
model = Bounty
fields = ("description", "banner")
class UpdateBountyView(UpdateView):
form_class = BountyUpdateForm
model = Bounty
template_name = 'bounty/update.html'
...
def get_context_data(self, **kwargs):
context = super(UpdateBountyView, self).get_context_data(**kwargs)
description = context['form']['description']
value = description.value()
# Value equals what was initialized by the previous form.
I'm really curious why these two forms are interacting in this way. Both form fields are called 'description', but that doesn't explain why the initial data from one would be crossing over to the other. Restarting the server seems to temporarily get the second form to show the correct values, but as soon as the first one is loaded, the second follows suit.
Any help would be greatly appreciated!
After some more searching, I was able to determine that my second view was having self.initial set to the same values as the first form by the time dispatch was being run. I couldn't determine why, but found these related questions:
Same problem, but no accepted answer:
Django(trunk) and class based generic views: one form's initial data appearing in another one's
Different problem, but good answer:
Setting initial formfield value from context data in Django class based view
My workaround was overriding get_initial() on my first form, instead of setting self.initial['description'] directly.
class UpdateProfileView(FormMixin, DetailView):
form_class = UpdateProfileForm
model = Profile
template_name = 'profile/update.html'
def get_initial(self):
return {
'description': self.object.about
}
def get_context_data(self, **kwargs):
...
# Removed the following line #
# self.initial['description'] = profile.about
...
context['form'] = self.get_form()
return context
Hope this helps anyone else who runs into this same problem. I wish I knew more about Django class-based views to be able to understand why this happens to begin with. However, I was unable to determine where self.initial was being set, beyond the empty dict in FormMixin().

How do I get django url parameters from a view mixin?

Exactly what the title says. I have a mixin that needs to pull in the id of a model field in order to be useful. I assume the easy way to do that would be to pull it from the URL.
class StatsMixin(ContextMixin):
def get_stats_list(self, **kwargs):
# the ??? is the problem.
return Stats.objects.filter(id=???).select_related('url')
def get_context_data(self, **kwargs):
kwargs['stats'] = self.get_stats_list()[0]
print kwargs
return super(StatsMixin, self).get_context_data(**kwargs)
Here's the view implementation for reference.
class ResourceDetail(generic.DetailView, StatsMixin):
model = Submissions
template_name = 'url_list.html'
queryset = Rating.objects.all()
queryset = queryset.select_related('url')
You can access URL parameters in Django by using, self.args and self.kwargs.

Django ChoiceField initial setup not working

I have ModelForm where i use Django Forms.ChoiceField. Writing the value to the database works. But when i open the url, the dropdown list is not showing the previously selected value as selected value.
I tried setting initial=value, but it's not working as well.
class GameForm(forms.ModelForm):
gameCode = forms.ChoiceField(required=False)
def __init__(self, *args, **kwargs):
obj = AllGameCodes.objects.filter(game=game)
choices = []
choices.append(('', '-----------'))
for i in obj:
choices.append((i.code,i.description))
self.fields['gameCode'].choices = choices
in views.py,
game = games.objects.get(id=1)
form = GameForm(request.POST, initial={'code':game.code}
You must take game variable from kwargs. Also using ModelChoicefield may ease your solution
def __init__(self, *args, **kwargs):
super(GameForm, self).__init__(*args, **kwargs)
_game = kwargs.get("game"):
if _game:
self.fields['gameCode'] = ModelChoiceField(queryset=AllGameCodes.objects.filter(game=_game), required=False)
For future reference, you may use form = GameForm(instance=game) to load the form with the model data and write new data to that model.
Also instead of overwriting the form class, you can alter fields in your view
#views.py
game = games.objects.get(id=1)
form = GameForm(request.POST, instance=game)
form.fields['gameCode'].queryset = AllGameCodes.objects.filter(game=game)

How to render multiple objects using class based views

I try to render multiple objects using class based views but I get an error.
Here are my codes:
class AssociatedList(WizardRequiredMixin, TemplateView):
template_name = "profile/associated_accounts.html"
def get_context_data(self, **kwargs):
context = super(AssociatedList, self).get_context_data(**context)
all_envelopes = Envelope.objects.filter(
user=request.user).exclude_unallocate()
free_limit = account_limit(request, 15, all_envelopes)
facebook = FacebookProfile.user_profiles(request.user)
google = GoogleProfile.user_profiles(request.user)
twitter = TwitterProfile.user_profiles(request.user)
context.update = ({
'facebook': facebook,
'google': google,
'twitter': twitter,
'free_limit': free_limit,
})
return context
Error:
local variable 'context' referenced before assignment
I've always overridden get_context_data by calling super at the beginning of the function and then appending context -
def get_context_data(self, *args, **kwargs):
context = super(AssociatedList, self).get_context_data(*args, **kwargs)
all_envelopes = Envelope.objects.filter(
user=self.request.user).exclude_unallocate()
free_limit = account_limit(self.request, 15, all_envelopes),
facebook = FacebookProfile.user_profiles(self.request.user),
google = GoogleProfile.user_profiles(self.request.user),
twitter = TwitterProfile.user_profiles(self.request.user),
context.update({
'facebook': facebook,
'google': google,
'twitter': twitter,
'free_limit': free_limit,
})
return context
This is the pattern used in the docs here.
UPDATE
The error you've just added suggests an error with your class. It sounds like you need to define either a queryset attribute or a model attribute.
The ListView class that you're inheriting from requires you to either define the model that the View returns (ie YourModel.objects.all()). Or else the specific queryset to be returned (eg YourModel.objects.filter(your_field=some_variable)).
Because this is a ListView, you need to tell it what you are going to list with either a model or queryset. You don't want to use a ListView in this case since you are overriding get_context_data so you should probably use a TemplateView or something similar.
Try something like this:
class AssociatedList(WizardRequiredMixin, ListView):
template_name = "profile/associated_accounts.html"
model = Envelope
def get_queryset(self):
return Envelope.objects.filter(user=self.request.user).exclude_unallocate()
def get_context_data(self, **kwargs):
context = super(AssociatedList, self).get_context_data(**kwargs)
context.update({
'facebook': FacebookProfile.user_profiles(self.request.user),
'google': GoogleProfile.user_profiles(self.request.user),
'twitter': TwitterProfile.user_profiles(self.request.user),
'free_limit': account_limit(self.request, 15, context['envelope_list']),
})
return context
You don't need model having queryset, but it is good practice to define it.
In template use object_list or envelope_list instead of all_envelopes and you should be good to go.
P.S. http://ccbv.co.uk/ good source of knowledge about CBV.