Based on model multiselectfield show result in template django - django

based on multiple choice field i want to show result in template but I have no idea how to do as you can see in this model i give lunch choice to students base on lunch choice i want to show result but it is not working for ex if he select sandwich the result after submit will you sandwich will be ready and same for others
from multiselectfield import MultiSelectField
class student(models.Model):
lunch_choice = [
('Sandwich', 'Sandwich'),
('Salad', 'Salad'),
('omlete', 'omlete'),
]
name = models.CharField(max_length=70, blank=False)
classs = models.CharField(max_length70, blank=True)
lunch = MultiSelectField(choices=lunch_choice, blank=True)
def __str__(self):
return self.name
i tried in my HTML and it didn't work
{% if student.classs %}
{% if student.lunch == 'Sandwich' %}
<p> your sandwich will be ready</p>
{% endif %}
{%endif%}
and in form.py using widget
widgets = {
'lunch':forms.CheckboxSelectMultiple(attrs={'id':'lunch'}),
}
my views.py
def preview(request):
student = student.objects.all()
return render(request, 'preview.html',{'student':student})

OP can create a model for lunches (it would enable to create new lunches, edit and delete). Then, in the Student model create a lunch with a ManyToManyField, like
lunch = models.ManyToManyField(Lunch, blank=True)
Note the usage of blank=True to not require the field in the forms.
Then, when one generates a form based on that model, it'll create an experience just like the one in Django Admin where one can select multiple ones.
One can then show it to the user in a template.
If one doesn't like the experience of the form and want to make it more user friendly, there are some articles out there explaining that
Django Forms for Many-to-Many Fields
How To Add Tags To Your Blog (A Django ManyToManyField Example)

acc to me there is no such way by which u can show the result base on selected option because i also tried to use that and look for answers on internet but didn't find anything and creator of that repo is also not responding although I would recommend you to use models many to many field It will allow user to select more than one option like multiselectfield like this
first, create models
class Lunch(models.Model):
title = models.CharField(max_length=200)
def __str__(self):
return self.title
then add this in student models
lunch = models.ManyToManyField(Lunch, blank=True, related_name="lunch")
then add your option in lunch model
and it in your template to show result base on selected option
{% if student.classs %}
{% for Lunch in student.lunch.all %}
{% if Lunch.title == 'Sandwich' %}
<p> your sandwich will be ready</p>
{% endif %}
{% endfor %}
{%endif%}
it will work

This happens because the string is being compared to type: type(aaa[0].lunch) <class 'multiselectfield.db.fields.MSFList'>. Printed the data type 'type(aaa[0].lunch)' of the first value from the database in the view. Used stringformat:'s' to convert data to string in template. Here you can read about the conversion:
conversion
transformation type:
replace 'samplesite' with the name of your application.
urls.py
urlpatterns = [
path("Test/", Test, name = 'Test'),
]
views.py
def Test(request):
aaa = student.objects.all()
print('type(aaa[0].lunch)', type(aaa[0].lunch))
context = {'fff': aaa}
return render(request, 'samplesite/lunch.html', context)
lunch.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
{% for aa in fff %}
{% if aa.lunch|stringformat:'s' == 'Sandwich' %}
<p>{{aa.lunch}}</p>
<p>{{aa.name}}</p>
{% endif %}
{% endfor %}
</body>
</html>
settings in settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
django version 4.1

Related

Adding extra content to Class Based View and filtering it

I've built a for-loop in my HTML template and its nearly working. The issue I'm having is its listing Matches that are apart of a different tour.
I think the way to fix this is adding a filter to the view that basically says "only pull in the matches to do with this tour" which is what I've tried to do below in the Match.objects.filter() but it isnt working and I'm not sure why.
class CricketCalendar(generic.ListView):
template_name="monthly_view/cricket-monthly-view.html"
context_object_name='cricket_monthly_view'
queryset = CricketMonthlyView.objects.all()
def get_context_data(self, **kwargs):
context = super(CricketCalendar, self).get_context_data(**kwargs)
context['Tour'] = Tour.objects.all()
context['Match'] = Match.objects.filter(tour=self.request.Tour)
return context
I have also tried the following and neither worked:
self.kwargs['pk']
self.kwargs['Tour']
Edit, forgot to add the following:
Monthly View models.py:
class CricketMonthlyView(models.Model):
tour = models.ForeignKey('cricket.Tour', on_delete=models.CASCADE,
related_name='tour_name')
match_id = models.ForeignKey('cricket.Match', on_delete=models.CASCADE)
and the URLs.py:
url(r'^monthly-view/$', monthly_view.CricketCalendar.as_view(), name='cricket-monthly'),
Cricket models.py:
class Tour(models.Model):
name = models.CharField(max_length=200)
tier_level = models.ForeignKey('sports.Tier')
country = CountryField()
class Match(models.Model):
tour = models.ForeignKey('Tour', on_delete=models.CASCADE)
And the HTML Template:
{% for match_info in cricket_monthly_view %}
{% for tour in Tour %}
<ul>
<li>{{tour.name}}</li>
</ul>
{% for match in Match %}
<ul>
<li>{{match.home_team}}</li>
<li>{{match.away_team}}</li>
</ul>
{% endfor %}
{% endfor %}
{% endfor %}
This is a great place for adding a break-point. You pretty much want to know the fields on your context, and on self. Add import pdb; pdb.set_trace() in get_context_data, and you'll be able to see the fields on your objects. Use dir(obj) and obj.keys() in order to see all the fields on something.
Alternatively, if you have access to the tour object in your context variable, in your template you can get its matching Matches with tour.match_set.all
Also, be careful about naming the context variable Tour with a capital T, because that's the name of your model.

Filter a Django form select element based on a previously selected element

Let's consider the following models
models.py
Class Brand(models.Model):
company_name = models.CharField(max_length=100)
class CarModel(models.Model):
brand = models.ForeignKey(Brand)
name = models.CharField(max_length=100)
Class FleetCars(models.Model):
model_car = models.Foreignkey(CarModel)
What is the best way to solve this problem in django?
Suppose a form (for insertions in FleetCars) consists of two select elements, like this:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<br />Brand:
<select>
<option value="Brand1">Brand1</option>
<option value="Brand2">Brand2</option>
</select>
<br />
<br />Model:
<select>
<option value="Model1_B1">Model1_B1</option>
<option value="Model1_B2">Model1_B2</option>
</select>
</body>
</html>
In this case, I want the options in the second select to depend on the value selected in the first. For example, if the user chose Brand1 for a Brand in the first select, the second select would be filtered with only cars whose Brand was Brand1, that is, only "Model1_B1".
Obs.
I saw many solutions with forms.ModelChoiceField, but only works with edit and since the user do not change the brand.
After hours and hours of research, without success, I decided to try to solve on my own. The solution that I found maybe don't be the best or the more elegant, but is working. (For download full Django project, click on this repo => https://github.com/Sidon/djfkf/.)
models.py
from django.db import models
class Brand(models.Model):
company_name = models.CharField(max_length=100)
def __str__(self):
return self.company_name
class Car(models.Model):
brand = models.ForeignKey(Brand)
name = models.CharField(max_length=100)
def brand_name(self):
return self.brand.company_name
def __str__(self):
return self.name
class Fleet(models.Model):
car = models.ForeignKey(Car)
description = models.CharField(max_length=100)
def car_name(self):
return self.car.name
def brand(self):
return self.car.brand.company_name
def __str__(self):
return self.description
The goal is to register cars on the fleet. The only fields that are will be recorded: Car (foreign key) and description. On the form, there will be one select element for brands that will work just only as a helper for to filter the car's combo box.
forms.py
import json
from django import forms
from .models import *
class RegCarForm(forms.ModelForm):
dcars = {}
list_cars = []
for car in Car.objects.all():
if car.brand.company_name in dcars:
dcars[car.brand.company_name].append(car.name)
else:
dcars[car.brand.company_name] = [car.name]
list_cars.append((car.name,car.name))
brands = [str(brand) for brand in Brand.objects.all()]
brand_select = forms.ChoiceField(choices=([(brand, brand) for brand in brands]))
car_select = forms.ChoiceField(choices=(list_cars))
brands = json.dumps(brands)
cars = json.dumps(dcars)
class Meta:
model = Fleet
fields = ('brand_select', 'car_select', 'description',)
RegCarForm is a form for register cars, there are three fields: brand_select, car_select, and description. In addition, I defined two JSON attributes: 1) a dictionary whose keys are brands (strings) and values are lists of respective's cars and 2) A list of strings that represent the brands. Those two attributes will work as helpers for JS functions.
views.py
from django.shortcuts import render
from .forms import RegCarForm
from .models import *
def regcar(request):
if request.method == 'POST':
car_form = RegCarForm(data=request.POST)
if car_form.is_valid():
cdata = car_form.cleaned_data.get
car_selected = Car.objects.filter(name=cdata('car_select'))
reg1 = Fleet(car_id=car_selected[0].id, description=cdata('description'))
reg1.save()
else:
print ('Invalid')
else:
car_form = RegCarForm()
return render(request, 'core/regcar.html', {'car_form': car_form})
The view is practically auto-explanatory. Assigns the Form to the car_form variable, render the template core/regcar.html and, after Post, make the validation of the form and save the data.
regcar.html (template django)
{% extends "base.html" %}
{% block head %}
{% endblock %}
{% block content %}
<h1>Registering cars on the fleet. <br />(Populate one drop down based on selection in another)</h1>
<p>Change the contents of drop down Car based on the selection in dropdown Brand, using Django-forms + Javascritp</p>
<div class="select-style">
<form action="." method="post">
{% csrf_token %}
{{ car_form.as_p }}
<p><input type="submit" value="Register a car"></p>
</form>
</div>
{% endblock %}
{% block js %}
{% include "js1.html" %}
{% endblock %}
The template only just renders the form and load the script JS. Nothing else.
Finally, the js script, that makes the hard work.
{% block js %}
<script language="javascript">
$('#id_brand_select').change(function() {populateCar(this)});
$('#id_description').addClass('descriptions');
cars = {{ car_form.cars | safe }}
brands = {{ car_form.brands | safe}};
populateBrand();
$("#id_car_select").empty();
$("#id_car_select").append('<option value="" disabled selected>First select a brand</option>');
function populateBrand() {
$('#id_brand_select').empty();
$("#id_brand_select").append('<option value="" disabled selected>Select your option</option>');
$.each(brands, function(v) {
$('#id_brand_select')
.append($("<option></option>")
.attr("value", brands[v])
.text(brands[v]));
});
}
function populateCar(event) {
brand = $("#id_brand_select option:selected").text();
$("#id_car_select").empty();
$("#id_car_select").append('<option value="" disabled selected>Select your option</option>');
for (let [b, bcars] of Object.entries(cars)) {
if (b == brand) {
//alert(b);
for (car in bcars) {
$('#id_car_select')
.append($("<option></option>")
.attr("value", bcars[car])
.text(bcars[car]));
}
}
}
}
</script>
{% endblock %}
When the document is loaded, this script assigns the change event of brand_select (combo for selection of brand) to the function poplulateCar, assign the form's JASON attributes (cars and brands) to a JS variables and call the populateBrand function.
Links:
Full project in Django:
https://github.com/Sidon/djfkf/
class Country(models.Model):
country_name=models.CharField(max_length=10, blank=True, null=True)
class State(models.Model):
state_name=models.CharField(max_length=10, blank=True, null=True)
class MyCustomModal(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, blank=True)
state = models.ForeignKey(State, on_delete=models.CASCADE, null=True, blank=True)
Here is my Form
class MyCustomForm(forms.ModelForm):
class Meta:
model = MyCustomModal
fields = [
'country',
'state',
]
def __init__(self, *args, **kwargs):
super(MyCustomForm, self).__init__(*args, **kwargs)
self.fields['country'] = forms.ChoiceField(choices=[('1','india'),('2','US')])
self.fields['state'].queryset = State.objects.filter(pk=2)

Filtering field in DJango in the URL and in the view

Lets say I have a model with 2 fields:
class Bands(models.Model):
id = models.IntegerField(db_column='ID', primary_key=True)
name = models.CharField(db_column='NAME')
type = models.CharField(db_column='TYPE')
...
What I want to do is to list all the fields data with just one template. For example:
{% block content %}
{{ field_name }}
<ul>
{% for band in bands %}
<li>{{ band }}</li>
{% endfor %}
</ul>
{% endblock %}
So, how should I make my url?
url(r'^band/$', views.band, name='band')
or
url(r'^band/(?P<band>\w+)/$', views.band, name='band')
The link to that page would be:
Name
In the view I'm taking the values as this:
def band(request, field):
results = Results.objects.all()
names = [n.name for n in results]
types = [t.type for t in results]
if field == 'name':
bands = names
else:
bands = types
return render(request, 'band.html', {'bands': bands, 'field_name': field})
Is this the right way to do this (in the view and the url)? Thanks in advance.
Well, the simplest thing to do is use the DetailView.
from .models import Band
class BandDetailView(DetailView):
model = Band
And in urls.py something like:
from band.views import BandDetailView
url(r'^band/(?P<pk>\d+)/?$', BandDetailView.as_view(), name='band-detail')
And in the template:
{% url 'band-detail' pk=1 %}
That said, your model doesn't make much sense to me, as does the Led Zeppelin vs. Deep Purple bits in the view. Can you explain your project / need a bit more?

Django filtering and querying: do it in views.py, template, or filters?

So I am working on a small Django project, which for the moment doesn't require optimization. But to prepare for the future, I'd like to know a bit more about the three approaches.
For instances, as part of the models, I have User and UserProfile, Transaction.
class User(models.Model):
name = ...
email = ...
class UserProfile(models.Model):
user = models.ForeignKey(User, related_name='profile')
photo = models.URLField(...)
...
class Transaction(models.Model):
giver = models.ForeignKey(User, related_name="transactions_as_giver")
receiver = models.ForeignKey(User, related_name='transactions_as_receiver')
...
I frequently need to do something like "return transactions that the request.user is giver or receiver", or "return the profile photo of a user". I have several choices, for instance to get a list of pending transactions and photos of both parties, I can do it at views.py level:
1.
#views.py
transactions = Transaction.objects.filter(Q(giver=request.user)|Q(receiver=request.user))
for transaction in transactions:
giver_photo = transactions.giver.profile.all()[0].photo
# or first query UserProfile by
# giver_profile = UserProfile.objects.get(user=transaction.giver),
# then giver_photo = giver_profile.photo
#
# Then same thing for receiver_photo
transaction['giver_photo'] = giver_photo
...
Or I can do it more on template level:
# some template
<!-- First receive transactions from views.py without photo data -->
{% for t in transactions %}
{{t.giver.profile.all.0.photo}}, ...
{% endfor %}
Or I can move some or even all of the above stuffs into filters.py
# some template
{{ for t in request.user|pending_transactions }}
{{ t.giver|photo }} {{ t.receiver|photo }}
{{ endfor }}
where photo and pending_transactions are roughly the same code in original views.py but moved to a filter.
So I wonder is there a best practice/guide line on how to choose which approach?
From Django documentation, lower level is faster, and therefore 2. 3. should be slower than 1; but how about comparing the 2. and 3.?
In getting a user photo, which of the two should be recommended, transactions.giver.profile.all()[0].photo OR profile = UserProfile.objects.get(...) --> photo = profile.photo?
Move this logic into models and managers. Views and templates must be as short as possible.
class User(models.Model):
...
def transactions(self):
return Transaction.objects.filter(Q(giver=self)|Q(receiver=self))
def photo(self):
return self.profile.all().first().photo
So the template will be:
{% for t in request.user.transactions %}
{{ t.giver.photo }} {{ t.receiver.photo }}
{% endfor %}
My experience says that business logic in model as much easier to test, support and reuse than in the views/templates.

Why won't date_based.archive_month in Django 1.3 work to show my blog posts?

I'm just trying to list my blog posts for a certain month in a certain year, but none of my posts are showing. When I type in the correct url: 2011/nov, no posts show up and I have Nov. 2011 posts saved in my admin.
Also, for some reason, my css file isn't being taken into account. When I go to the url, 2011/nov, I just get html with no styling and none of my posts. What am I doing wrong here?
#models.py
class Post(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(max_length=120, unique = True)
body = models.TextField()
published = models.DateTimeField(default=datetime.now)
categories = models.ManyToManyField(Category)
def __unicode__(self):
return self.title
#urls.py
info_dict = {
'queryset': Post.objects.all(),
'date_field': 'published',
}
urlpatterns = patterns('',
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$',
date_based.archive_month,
dict(info_dict, template_name='blog/archive.html',)),
#blog/archive.html
<link href="../static/style.css" rel="stylesheet" type="text/css" media="screen" />
.
.
.
{% for post in post_list %}
<h3 class="title">{{post.title}}
</h3>
{% endfor %}
The CSS is not showing because you define it relatively to be ../static/style.css. When the address is /2011/jan the browser tries to get the css from /2011/static/style.css. Fix: Set the path to be absolute: /static/style.css.
You should be looping through object called object_list instead of post_list.
{% for post in object_list %}
The context variable that holds the post is called object_list not post_list so you should have:
{% for post in object_list %}
...
{% endfor %}
https://docs.djangoproject.com/en/dev/ref/generic-views/?from=olddocs#django-views-generic-date-based-archive-month
Your css file should be:
and if you are developing locally you need to set up the development server to server your media for you:
https://docs.djangoproject.com/en/dev/howto/static-files/#using-django-contrib-staticfiles
In addition to what pastylegs wrote above, you should also change this line
published = models.DateTimeField(default=datetime.now)
to this:
published = models.DateTimeField(auto_now_add=True)
In Python, named arguments are only evaluated once. This means that the default published value is the time your server last compiled the models.py file. Django offers a solution to this: setting the parameter auto_now_add=True, makes django use the actual current time for the field, when it's first created. Similarly, setting auto_now=True makes django set the current time for the field whenever it's saved.