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
Related
i have a model which has a foreign key relation with two oder models one of them is 'level'.
the view knows in which level you are based on a session variable,
and then filter the lessons
this is the lesson model:
class Lesson(models.Model):
level = models.ForeignKey(Level,on_delete=models.CASCADE)
subject = models.ForeignKey(Subject,on_delete=models.CASCADE)
chapiter = models.CharField(max_length=200)
lesson = models.CharField(max_length=200)
skill = models.CharField(max_length=200)
vacations = models.IntegerField()
link = models.URLField(max_length=700,null=True,blank=True)
remarques = models.TextField(null=True,blank=True)
order = models.IntegerField()
created = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now=True)
state = models.BooleanField(default=False)
now this is my cbv to create a new lesson:
class GlobalLessonView(CreateView):
model = Lesson
form_class = GlobalLessonForm
success_url = reverse_lazy('globalform')
and this is the form:
class GlobalLessonForm(forms.ModelForm):
class Meta:
model = Lesson
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['subject'].queryset = Subject.objects.none() #change to .all() to see list of all subjects
if 'level' in self.data:
try:
level_id = int(self.data.get('level'))
self.fields['subject'].queryset = Subject.objects.extra(where=[db_name+'.scolarité_subject.id in( select subject_id from '+db_name+'.scolarité_levelsubject where level_id='+level_id+')'])
except (ValueError, TypeError):
pass # invalid input from the client; ignore and fallback to empty City queryset
elif self.instance.pk:
self.fields['subject'].queryset = self.instance.level.subject_set
one of the main conditions is to filter level by a session variable
but the form does not accept request.session
so is there any way to change the levels that shows up at the form from the class based view,or there any way to pass request.session to form.py
Add this to GlobalLessonView:
def get_form_kwargs(self):
"""Pass request to form."""
kwargs = super().get_form_kwargs()
kwargs.update(request=self.request)
return kwargs
Then change the constructor definition in GlobalLessonForm to:
def __init__(self, request, *args, **kwargs):
Then you will be able to reference request.session in GlobalLessonForm.
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.
The Model flow Topic -> Section -> Article.
I am building an Update View for my FAQ project to update already created Articles. I want the Form to provide a selection of Sections based on the Topic the Article was created under. As I already have the Articles PK passed in through the URL I was hoping to use it to walk back up to the Topic when creating my filter. I am receiving an object has no attribute ‘section’ error when the template is attempting to render the form on line self.fields['section'].queryset = Section.objects.filter(topic_id=self.section.topic.id) in the UpdateAriticleForm. I need help to figure out my query filter.
The URL:
url(r'^ironfaq/article/update/(?P<pk>\d+)/$', ArticleUpdateView.as_view()),
The Form:
from django import forms
from .models import Topic, Section, Article
class CreateArticleForm(forms.ModelForm):
section = forms.ModelChoiceField(queryset=Section.objects.none())
def __init__(self, *args, **kwargs):
topic_pk = kwargs.pop('topic_pk')
super(CreateArticleForm, self).__init__(*args, **kwargs)
self.fields['section'].queryset = Section.objects.filter(topic_id=topic_pk)
class Meta:
model = Article
widgets = {
'answer': forms.Textarea(attrs={'data-provide': 'markdown', 'data-iconlibrary': 'fa'}),
}
fields = ('title','section','answer')
class UpdateArticleForm(forms.ModelForm):
section = forms.ModelChoiceField(queryset=Section.objects.none())
def __init__(self, *args, **kwargs):
super(UpdateArticleForm, self).__init__(*args, **kwargs)
self.fields['section'].queryset = Section.objects.filter(topic_id=self.section.topic.id)
class Meta:
model = Article
widgets = {
'answer': forms.Textarea(attrs={'data-provide': 'markdown', 'data-iconlibrary': 'fa'}),
}
fields = ('title','section','answer')
The View:
class ArticleUpdateView(UpdateView):
model = Article
form_class = UpdateArticleForm
template_name = "faq/form_create.html"
def form_valid(self, form):
article = form.save(commit=False)
article.activity_user = self.request.user.username
article.activity_date = datetime.datetime.now()
article.save()
self.success_url = "/ironfaq/%s/%s/%d" % (article.section.topic.slug,article.section.slug,article.id)
return super(ArticleUpdateView,self).form_valid(form)
The Models:
class Topic(Audit):
name = models.CharField(max_length=255)
icon = models.CharField(max_length=25,blank=True,null=True)
sort = models.SmallIntegerField()
slug = models.SlugField()
class Meta:
verbose_name_plural = "topics"
def __str__(self):
return self.name
class Section(Audit):
name = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
topic = models.ForeignKey(Topic,on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "sections"
def __str__(self):
return self.name
class Article(Audit):
title = models.CharField(max_length=255)
sort = models.SmallIntegerField()
slug = models.SlugField()
section = models.ForeignKey(Section,on_delete=models.CASCADE)
answer = models.TextField()
vote_up = models.IntegerField(default=0)
vote_down = models.IntegerField(default=0)
view_count = models.IntegerField(default=0)
class Meta:
verbose_name_plural = "articles"
def __str__(self):
return self.title
The answer to the this issue was not passing 'pk' as a argument to the form and to add get_form_kwargs to the view to enable the form to see the 'pk' passed in the URL.
Form:
class UpdateArticleForm(forms.ModelForm):
section = forms.ModelChoiceField(queryset=Article.objects.none())
def __init__(self, pk, *args, **kwargs):
super(UpdateArticleForm, self).__init__(*args, **kwargs)
self.fields['section'].queryset = Section.objects.filter(topic_id__exact=Article.objects.filter(id=pk).first().section.topic.id)
View:
class ArticleUpdateView(UpdateView):
model = Article
form_class = UpdateArticleForm
template_name = "faq/form_create.html"
def get_form_kwargs(self):
kwargs = super(ArticleUpdateView,self).get_form_kwargs()
kwargs.update(self.kwargs)
return kwargs
def form_valid(self, form):
article = form.save(commit=False)
article.activity_user = self.request.user.username
article.activity_date = datetime.datetime.now()
article.save()
self.success_url = "/ironfaq/%s/%s/%d" % (article.section.topic.slug,article.section.slug,article.id)
return super(ArticleUpdateView,self).form_valid(form)
I need to assign multiple CampaignTypes to a Campaign unsing Django FormsModels.
Selecting many CapaignTypes at once, adding the CapaignTypes to only one campaign. Thanks I will appreciate any help
class Campaign(models.Model):
client_id = models.ForeignKey(Company)
name = models.CharField(max_length=45, null=True)
campaign_status = models.ForeignKey(CampaignStatus)
def __str__(self):
return self.name
class Campaign_type(models.Model):
campaign_type = models.CharField(max_length=45)
client_id = models.ForeignKey(Company)
campaign_id = models.ManyToManyField(Campaign, verbose_name='Campaign(s)')
def __str__(self):
return self.campaign_type + ' ' + str(self.client_id)
My code in form.py
class CampaignCampaignTypeForm(forms.ModelForm):
class Meta:
model = CampaignType
exclude = ['campaign_id', 'client_id']
campaign_type = forms.ModelMultipleChoiceField(queryset=CampaignType.objects.all())
def __init__(self, *args, **kwargs):
company = kwargs.pop("company")
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['campaign_type'] = [t.pk for t in kwargs['instance'].campaing_type_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
My code in view.py
def add_campaign_type_to_campaign(request, campaign_id):
if not request.user.is_authenticated():
return render(request, 'campaign/login.html')
else:
client_user = ClientUser.objects.get(client=request.user.pk)
form = CampaignCampaignTypeForm(data=request.POST or None, company=client_user.company)
if form.is_valid():
campaigntype = form.save(commit=False).clean()
#client_user = ClientUser.objects.get(client=request.user.pk)
campaign = Campaign.objects.get(id=campaign_id)
campaigntype.campaign_id = campaign
campaigntype.save()
form.save_m2m()
# return render(request, 'campaign/detail_campaign.html', {'campaign_type': campaign_type})
context = {
"form": form,
}
Do you try forms.SelectMultiple widget? Or if you can using Bootstrap on frontend, Select2 is a good JS package to help you on multiple selection.
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.