Pass get_queryset in Context - django

Need help on passing the returned value from get_queryset to the context for rendering, I am reading the Django documentation on Class-based Views and I keep getting the same error name 'querySet' is not defined, any insight on what I'm doing wrong would be appreciated.
class SearchPropertyListView(ListView):
template_name = "search/search_list.html"
def get_queryset(self):
querySet = Property.objects.all()
city_or_neighborhood = self.request.GET.get('city_or_neighborhood')
category = self.request.GET.get('category')
purpose = self.request.GET.get('purpose')
if city_or_neighborhood != '' and city_or_neighborhood is not None:
querySet = querySet.filter(Q(city__title__icontains=city_or_neighborhood)
| Q(neighborhood__title__icontains=city_or_neighborhood)
).distinct()
elif category != '' and category is not None:
querySet = querySet.filter(category__title=category)
elif purpose != '' and purpose is not None:
querySet = querySet.filter(purpose__title=purpose)
return querySet
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
city = City.objects.all().annotate(
num_property=Count("property")).order_by("-num_property")
categories = Category.objects.all()
purposes = Purpose.objects.all()
featured = list(Property.objects.filter(featured=True))
shuffle(featured)
context['city'] = city
context['categories'] = categories
context['featured'] = featured
context['purposes'] = purposes
context['querySet'] = querySet
return context

In your get_context_data(), you have querySet which is not defined:
def get_context_data(self, *args, **kwargs):
.....
context['purposes'] = purposes
context['querySet'] = querySet <----- Here
return context
So, you should define your querySet like:
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
city = City.objects.all().annotate(
num_property=Count("property")).order_by("-num_property")
categories = Category.objects.all()
purposes = Purpose.objects.all()
featured = list(Property.objects.filter(featured=True))
querySet = self.get_queryset()
shuffle(featured)
context['city'] = city
context['categories'] = categories
context['featured'] = featured
context['purposes'] = purposes
context['querySet'] = querySet
return context
*Note:- If you are expecting querySet from get_queryset(), then know that these are two different methods and you defined querySet locally. Or, you have to get that from self.get_queryset() as mentioned by #OlegŠ¢.

Related

Can I use a single search bar for searching different things?

I'm trying to use a single search bar for searching different models. Is it possible to handle it with one view?
my views.py file:
class SearchResultsView(ListView):
model = Food
template_name = 'restaurant/food_search_results.html'
context_object_name = 'data'
def get_queryset(self):
query = self.request.GET.get('search')
if query is not None:
return Food.objects.filter(name__icontains=query)
else:
return Food.objects.none()
my models.py file:
class Food(models.Model):
name = models.CharField(max_length=100)
image = models.ImageField(upload_to=upload_path)
description = models.TextField(max_length=500)
created = models.DateTimeField(auto_now_add=True)
meal_category = models.ManyToManyField(MealCategory, related_name="meal")
food_restaurant_category = models.ManyToManyField(FoodRestaurantCategory, related_name="food_cat")
class Restaurant(models.Model):
name = models.CharField(max_length=100)
You can use the context to pass the second model filtered list:
class SearchResultsView(ListView):
model = Food
template_name = 'restaurant/food_search_results.html'
context_object_name = 'data'
def get_queryset(self):
query = self.request.GET.get('search')
if query is not None:
return Food.objects.filter(name__icontains=query)
else:
return Food.objects.none()
def get_context_data(self, **kwargs):
query = self.request.GET.get('search')
context = super(SearchResultsView, self).get_context_data(**kwargs)
if query is not None:
filtered_restaurants= Restaurant.objects.filter(name__icontains=query)
else:
filtered_restaurants= Restaurant.objects.none()
context.update({
'restaurants_list': filtered_restaurants
})
return context

How to filter queryset in django inline form?

I want to filter certain modelfield in my inlineform to specific user and company.
But was unable to do in django inline formset.
This are my models:
class Purchase(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)
party_ac = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='partyledger')
purchase = models.ForeignKey(Ledger1,on_delete=models.CASCADE,related_name='purchaseledger')
total = models.DecimalField(max_digits=10,decimal_places=2,null=True,blank=True) purchases
class Stock_total(models.Model):
purchases = models.ForeignKey(Purchase,on_delete=models.CASCADE,null=True,blank=False,related_name='purchasetotal')
stockitem = models.ForeignKey(Stockdata,on_delete=models.CASCADE,null=True,blank=True,related_name='purchasestock')
quantity_p = models.PositiveIntegerField()
rate_p = models.DecimalField(max_digits=10,decimal_places=2)
grand_total = models.DecimalField(max_digits=10,decimal_places=2,null=True,blank=True)
My views:
class Purchase_createview(ProductExistsRequiredMixin,LoginRequiredMixin,CreateView):
form_class = Purchase_form
template_name = 'stockkeeping/purchase/purchase_form.html'
def get_context_data(self, **kwargs):
context = super(Purchase_createview, self).get_context_data(**kwargs)
context['profile_details'] = Profile.objects.all()
company_details = get_object_or_404(Company, pk=self.kwargs['pk'])
context['company_details'] = company_details
if self.request.POST:
context['stocks'] = Purchase_formSet(self.request.POST)
else:
context['stocks'] = Purchase_formSet()
return context
def form_valid(self, form):
form.instance.user = self.request.user
c = Company.objects.get(pk=self.kwargs['pk'])
form.instance.company = c
context = self.get_context_data()
stocks = context['stocks']
with transaction.atomic():
self.object = form.save()
if stocks.is_valid():
stocks.instance = self.object
stocks.save()
return super(Purchase_createview, self).form_valid(form)
In my forms I have tried this:
class Stock_Totalform(forms.ModelForm):
class Meta:
model = Stock_Total
fields = ('stockitem', 'Quantity_p', 'rate_p', 'Disc_p', 'Total_p')
def __init__(self, *args, **kwargs):
self.User = kwargs.pop('purchases.User', None)
self.Company = kwargs.pop('purchases.Company', None)
super(Stock_Totalform, self).__init__(*args, **kwargs)
self.fields['stockitem'].queryset = Stockdata.objects.filter(User = self.User, Company= self.Company)
self.fields['stockitem'].widget.attrs = {'class': 'form-control select2',}
self.fields['Quantity_p'].widget.attrs = {'class': 'form-control',}
self.fields['rate_p'].widget.attrs = {'class': 'form-control',}
self.fields['Total_p'].widget.attrs = {'class': 'form-control',}
Purchase_formSet = inlineformset_factory(Purchase, Stock_Total,
form=Stock_Totalform, extra=6)
But the filtering of queryset is not showing any item if it is present under specific User and also under specific company.
Can anyone help me with the exact query that will filter objects under specific user and company.
Thank you
You need to remove queryset in __init__ of the form and pass instance parameter while creating inlineformset_factory.
Purchase_formSet = inlineformset_factory(
Purchase,
Stock_Total,
form=Stock_Totalform,
extra=6,
)
PurchaseForm = Purchase_formSet(instance=Stockdata.objects.filter(User='1'))
This is static method which means, the filter will be fixed and won't be changed based on user input in form.
If you want to have dynamic filter based on user input in some of the form fields, this article explains it very well and in detail.

Django DetailView: filtering object based off primary key

I'm trying to filter an object based off of the primary key in my detailed view. Is there a way I can call my primary key in my views.py or some other way I can filter accordingly? Here's my code:
models.py
class Accounts(models.Model):
account_name = models.CharField(max_length=50)
pricing_id = models.ForeignKey('Pricing')
class OrderRecords(models.Model):
order_id = models.ForeignKey('Orders')
account_id = models.ForeignKey('Accounts')
item_id = models.ForeignKey('Items')
views.py
class AccountDetailView(generic.DetailView):
model = Accounts
template_name = "orders/accountdetail.html"
def get_context_data(self, **kwargs):
context = super(AccountDetailView, self).get_context_data(**kwargs)
context['orderrecords'] = OrderRecords.objects.filter(????????)
return context
Update:
So this was the change I made:
views.py
class AccountDetailView(generic.DetailView):
model = Accounts
template_name = "orders/accountdetail.html"
def get_context_data(self, **kwargs):
pk = self.kwargs['pk']
context = super(AccountDetailView, self).get_context_data(**kwargs)
context['orderrecords'] = OrderRecords.objects.filter(account_id=pk)
return context
Yes, in your views, simply call:
def get_context_data(self, **kwargs):
pk = kwargs.get('pk') # this is the primary key from your URL
# your other code
context = super(AccountDetailView, self).get_context_data(**kwargs)
context['orderrecords'] = OrderRecords.objects.filter(????????)
return context

objects filter on base of url request

I have two similar classes, query filter is county code DE or NL.
Is possible to make a objects filter on base of url name and keep only one class? For example, if i point my browser to
127.0.0.1:8000/germany
django will call to filter
feed__country__name='DE'
and
127.0.0.1:8000/netherland
will use
feed__country__name='NL'?
My URL:
url(r'^netherland/$', NLFeedList.as_view(), name='nl'),
url(r'^germany/$', DEFeedList.as_view(), name='de'),
VIEWS:
class NLFeedList(PaginationMixin, ListView):
model = FeedItem
template_name = 'nl_feed.html'
context_object_name = 'feed_items'
paginate_by = 20
def get_queryset(self):
items = FeedItem.objects.filter(feed__country__name='NL')
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(NLFeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name='NL')
return context
class DEFeedList(PaginationMixin, ListView):
model = FeedItem
template_name = 'de_feed.html'
context_object_name = 'feed_items'
def get_queryset(self):
items = FeedItem.objects.filter(feed__country__name='DE')
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(DEFeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name='DE')
return context
You can do something like:
urls.py
url(r'^(?P<country>germany|netherland)/$', FeedList.as_view(), name='feedlist')
and the view:
class FeedList(PaginationMixin, ListView):
model = FeedItem
context_object_name = 'feed_items'
match = {'germany':'DE','netherland':'NL'}
def get_queryset(self):
code = self.match[self.kwargs['country']]
items = FeedItem.objects.filter(feed__country__name=code)
self.template_name = '%s_feed.html' % code.lower()
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(FeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name=self.match[self.kwargs['country']])
return context
Also, perhaps you don't need two templates else only one, in this case just remove this line self.template_name = '%s_feed.html' % code.lower() and set the template_name accordingly.
Change your url to
url(r'^(?P<country>netherland|germany)/$', NLFeedList.as_view(), name='nl'),
Then access this new <country> parameter in your view using
country = self.kwargs['country']
Then do the necessary if country = '...': code block in your view.

Dynamic field names in Django Mixin

I have these class based ListView's which I would like to filter by date. I have a simple mixin
to display the filterform, which works great:
class MonthYearFormMixin(object):
def get_context_data(self, **kwargs):
context = super(MonthYearFormMixin, self).get_context_data(**kwargs)
context['monthyearform'] = MonthYearForm(self.request.GET)
return context
I would like to extend the functionality of this mixin to include the queryset filtering, but my models
have different date fields that need to be filtered on, one might be start_date, another might be
invoice_date. Of course someone might say, "rename them all 'date'", but that's not representative
of my models and furthermore, I might have a model with start_date and end_date, but only want to filter
on start_date. Here are my views:
class SentList(MonthYearFormMixin, ListView):
model = Sent
context_object_name = 'object'
template_name = 'sent_list.html'
def get_queryset(self):
qs = self.model.objects.all()
if 'month' in self.request.GET:
if int(self.request.GET['month']) > 0:
qs = qs.filter(start_date__month=self.request.GET['month'])
if 'year' in self.request.GET:
if int(self.request.GET['year']) > 0:
qs = qs.filter(start_date__year=self.request.GET['year'])
return qs
class ReceivedList(MonthYearFormMixin, ListView):
model = Received
context_object_name = 'object'
template_name = 'received_list.html'
def get_queryset(self):
qs = self.model.objects.all()
if 'month' in self.request.GET:
if int(self.request.GET['month']) > 0:
qs = qs.filter(invoice_date__month=self.request.GET['month'])
if 'year' in self.request.GET:
if int(self.request.GET['year']) > 0:
qs = qs.filter(invoice_date__year=self.request.GET['year'])
return qs
The only thing that's different is the name of the date field, so it's frustrating to have to repeat
this code.
Why not create a member variable called date_field_name where you store the name of the field names which should be processed by your QuerySet processor mixin?
This list would be defined in the class which uses the mixin.
Something like
class MonthYearFormMixin(object):
def get_context_data(self, **kwargs):
context = super(MonthYearFormMixin, self).get_context_data(**kwargs)
context['monthyearform'] = MonthYearForm(self.request.GET)
return context
def get_queryset(self):
qs = self.model.objects.all()
if 'month' in self.request.GET:
if int(self.request.GET['month']) > 0:
kwargs = {('%s__month' % self.date_field_name): self.request.GET['month']}
qs = qs.filter(**kwargs)
if 'year' in self.request.GET:
if int(self.request.GET['year']) > 0:
kwargs = {('%s__year' % self.date_field_name): self.request.GET['year']}
qs = qs.filter(**kwargs)
return qs
your views would look like this:
class SentList(MonthYearFormMixin, ListView):
model = Sent
context_object_name = 'object'
template_name = 'sent_list.html'
date_field_name = 'start_date'