Current user variable in ListView class - django

I want to execute a database query using the currently logged in user within a ListView class. Then after that I want to put those results into the extra_context variable so I can access them on the html page. After looking on different websites I found this piece of code:
class className(LoginRequiredMixin, ListView):
context_object_name = 'contextName'
template_name = 'app_list.html'
def get_queryset(self):
return Userproject.objects.filter(user=self.request.user)
How can I put the current user into a variable, that I can use later on in a database query so I can use it like this (I dont want to use the current user variable in the HTML. I want to access that variable within the class itself):
class className(LoginRequiredMixin, ListView):
def get_queryset(self):
return User.objects.filter(user=self.request.user)
user = THIS IS WHERE I WANT THE CURRENT USER VALUE
context = {
'friends': friends.Objects.filter(friendId = user.id)
}
model = User
template_name = friends/friend.html
context_object_name = 'friends'

you can override the get context data method.
def get_context_data(self, **kwargs):
context = super(ClassName, self).get_context_data(**kwargs)
context['user_obj'] = Userproject.objects.filter(user=self.request.user)
return context
you can avail user_obj in templates

Related

New to Django - get list of users with the most posts

First post and new to python and django.
I am trying to add context to a ListView so that I can display a list of top 5 most commented posts and also a list of top 5 most active users (users with most posts). I have got the first list working however can't work out the second list. Using the values method (i think it's a method) i've managed to query the database and get back a dictionary of user_id and posts count. My problem is that I want to display the username rather than the user_id. For some reason this query results in a dictionary rather than the full object. I've posted the code from views.py below.
class PostListView(ListView):
queryset = Article.objects.filter(published=True)
template_name = 'articles/index.html' #address of non default template
context_object_name = 'articles' #variable name passed to template
ordering = ['-pub_date']
#get query results for popular posts and most active users side bar
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['most_commented'] = Article.objects.annotate(comment_count=Count('comments')).order_by('-comment_count')[:5]
context['most_active'] = Article.objects.all().values('author').annotate(active=Count('author')).order_by('-active')[:5]
return context
Thank you for your help!
Nick
You're correct, values is a method that returns dicts. If you want the full object, there's no need to use values here:
context['most_active'] = Article.objects.all().annotate(active=Count('author')).order_by('-active')[:5]
You can then iterate through most_active in the template and access the username directly.
If you did want to use values, just pass the fields you want returned in the dict:
context['most_active'] = Article.objects.all().values('author__username').annotate(active=Count('author')).order_by('-active')[:5]
I think you are making it too complicated. You can annotate the User to obtain the most Users with the most published articles:
class PostListView(ListView):
queryset = Article.objects.filter(published=True)
template_name = 'articles/index.html' #address of non default template
context_object_name = 'articles' #variable name passed to template
ordering = ['-pub_date']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['most_commented'] = Article.objects.annotate(
comment_count=Count('comments')
).order_by('-comment_count')[:5]
context['most_active'] = User.objects.annotate(
narticles=Count('article')
).order_by('-narticles')[:5]
return context

HttpResponse error django generic template

I am able to render class based view generic ListView template using parameter hard coded in views.py.
class ResourceSearchView(generic.ListView):
model = creations
context_object_name = 'reviews'
template_name = 'reviews.html'
query = 'theory'
# def get(self, request):
# if request.GET.get('q'):
# query = request.GET.get('q')
# print(query)
queryset = creations.objects.filter(narrative__contains=query).order_by('-post_date')
However, when parameter is sent via form by GET method (below),
class ResourceSearchView(generic.ListView):
model = creations
context_object_name = 'reviews'
template_name = 'reviews.html'
query = 'theory'
def get(self, request):
if request.GET.get('q'):
query = request.GET.get('q')
print(query)
queryset = creations.objects.filter(narrative__contains=query).order_by('-post_date')
I receive this error
The view creations.views.ResourceSearchView didn't return an
HttpResponse object. It returned None instead.
Note that the parameter name q and associated value is being retrieved successfully (confirmed using print(query)).
So with CBV in Django, you have to return some kind of valid response that the interpreter can use to perform an actual HTTP action. Your GET method isn't returning anything and that's what is making Django angry. You can render a template or redirect the user to a view that renders a template but you must do something. One common pattern in CBV is to do something like:
return super().get(request, *args, **kwargs)
...which continues up the chain of method calls that ultimately renders a template or otherwise processes the response. You could also call render_to_response() directly yourself or if you're moving on from that view, redirect the user to get_success_url or similar.
Have a look here (http://ccbv.co.uk) for an easy-to-read layout of all the current Django CBVs and which methods / variables they support.
Thanks for the responses. Here is one solution.
class ResourceSearchView(generic.ListView):
model = creations
context_object_name = 'reviews'
template_name = 'reviews.html'
def get_queryset(self):
query = self.request.GET.get('q')
queryset = creations.objects.filter(narrative__contains=query).order_by('-post_date')
return queryset

Django: Display user's previous choices for a ModelForm in the template

I am trying to create a user profile page where users can see and update their preferences for certain things, like whether they are vegetarian, or have a particular allergy, etc. I want the data to be displayed as a form, with their current preferences already populating the form fields.
So I've created the following Model:
class FoodPreferences(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) # One user has one set of food prefs
vegetarian = models.BooleanField()
vegan = models.BooleanField()
...
that's referenced in my forms.py:
class FoodPreferencesForm(forms.ModelForm):
class Meta:
model = FoodPreferences
exclude = ('user', )
I've tried creating a view that inherits FormView and then referencing the form, like this:
class UserProfileView(generic.FormView):
template_name = "registration/profile.html"
form_class = FoodPreferencesForm
success_url = reverse_lazy('user_profile')
This saves the form to a instance of the model correctly, but obviously it just displays the blank form again, after updating, so the user has no idea what their current preferences are.
To implement this I thought I might need to override get() and post() to get the instance of FoodPreferences for the user, and then pass those values into the form like you would a request.POST object. However, firstly, I don't know how to do that, and secondly I'd be taking responsibility for correctly updating the database, which the FormView was already doing.
This is what I've got for that solution:
def get(self, request, *args, **kwargs):
prefs = FoodPreferences.objects.get(user=request.user)
form = self.form_class(prefs)
return render(request, self.template_name, {'form': form, })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if not form.is_valid():
return render(request, self.template_name, {'form': form, 'error': 'Something went wrong.'})
curr_prefs = FoodPreferences.objects.update_or_create(form.fields)
prefs.save()
return render(request, self.template_name, {'form': form, })
but I get a TypeError: argument of type 'FoodPreferences' is not iterable on the line in get():
form = self.form_class(prefs)
because it's not expecting a model instance.
Am I thinking about this in the right way? This seems like a common enough problem that Django would have something inbuilt to do it, but I can't find anything.
You should only rarely need to define get or post in a class-based view, and you definitely don't here.
To start with, you need to use a more appropriate base class for your view. Here you want to update an existing item, so you should use UpdateView.
Secondly, you need to tell the class how to get the existing object to update, which you can do by definining get_object. So:
class UserProfileView(generic.UpdateView):
template_name = "registration/profile.html"
form_class = FoodPreferencesForm
success_url = reverse_lazy('user_profile')
def get_object(self, queryset=None):
return self.request.user.foodpreferences
# or, if you aren't certain that the object already exists:
obj, _ = FoodPreferences.objects.get_or_create(user=self.request.user)
return obj

How to add data to context object in DetailView?

I need to write a DetailView in Django. I achieved this functionality. However, I need to add some more data along with the context object. How will I achieve this.
My generic view is:
class AppDetailsView(generic.DetailView):
model = Application
template_name = 'appstore/pages/app.html'
context_object_name = 'app'
I need to add one more variable to the context object:
response = list_categories(storeId)
How about using get_context_data
class AppDetailsView(generic.DetailView):
model = Application
def get_context_data(self, **kwargs):
context = super(AppDetailsView, self).get_context_data(**kwargs)
context['categories'] = list_categories(storeId)
return context

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.