I'm trying to build a form for scheduling a single (or double) elimination tournament. For example, consider a league which has teams TeamA, TeamB, TeamC, and TeamD (all of which are already defined in my database).
The form should look something like
Style: choice field - {single or double elimination}
Seed1: choice field - {TeamA or TeamB or TeamC or TeamD}
Seed2: choice field - {TeamA or TeamB or TeamC or TeamD}
Seed3: choice field - {TeamA or TeamB or TeamC or TeamD}
Seed4: choice field - {TeamA or TeamB or TeamC or TeamD}
This is what I have...
class EliminationForm(Form):
"""
Form for generating an elimination structure of Game instances
"""
choices = [(1, "Single Elimination"), (2, "Double Elimination")]
style = ChoiceField(choices=choices, widget=Select(attrs={'class':'form-control'}))
How would I set up this form to dynamically build the "Seed" fields for each team in the league?
Here's my models.py
class League(models.Model):
league_name = models.CharField(max_length=60)
class Team(models.Model):
league = models.ForeignKey('League')
team_name = models.CharField(max_length=60)
I think what you are looking for is a ModelChoiceField.
It will allow you to populate the dropdowns with the teams you have in the database:
class EliminationForm(Form):
"""
Form for generating an elimination structure of Game instances
"""
choices = [(1, "Single Elimination"), (2, "Double Elimination")]
style = ChoiceField(
choices=choices,
widget=Select(attrs={'class':'form-control'})
)
seed1 = ModelChoiceField(
queryset=Team.objects.all(),
)
seed2 = ModelChoiceField(
queryset=Team.objects.all(),
)
seed3 = ModelChoiceField(
queryset=Team.objects.all(),
)
seed4 = ModelChoiceField(
queryset=Team.objects.all(),
)
You can also filter the objects being used to only select teams of the same league, or only teams assigned to a league etc.
You may also want to add a __unicode__ function to the Team model to define how it is displayed in the dropdown.
class Team(models.Model):
league = models.ForeignKey('League')
team_name = models.CharField(max_length=60)
def __unicode__(self):
return self.team_name
Related
I'm using Django filters (django-filter) in my project. I have the models below, where a composition (Work) has a many-to-many instrumentations field with a through model. Each instrumentation has several instruments within it.
models.py:
class Work(models.Model):
instrumentations = models.ManyToManyField(Instrument,
through='Instrumentation',
blank=True)
class Instrument(models.Model):
name = models.CharField(max_length=100)
class Instrumentation(models.Model):
players = models.IntegerField(validators=[MinValueValidator(1)])
work = models.ForeignKey(Work, on_delete=models.CASCADE)
instrument = models.ForeignKey(Instrument, on_delete=models.CASCADE)
views.py:
import django_filters
class WorkFilter(django_filters.FilterSet):
instrument = django_filters.ModelMultipleChoiceFilter(
field_name="instrumentation__instrument",
queryset=Instrument.objects.all())
My filter works fine: it grabs all the pieces where there is the instrument selected by the user in the filter form.
However, I'd like to add the possibility of filtering the compositions with those exact instruments. For instance, if a piece contains violin, horn and cello and nothing else, I'd like to get that, but not a piece written for violin, horn, cello, and percussion. Is it possible to achieve that?
I'd also like the user to choose, from the interface, whether to perform an exact search or not, but that's a secondary issue for now, I suppose.
Update: type_of_search using ChoiceFilter
I made some progress; with the code below, I can give the user a choice between the two kinds of search. Now, I need to find which query would grab only the compositions with that exact set of instruments.
class WorkFilter(django_filters.FilterSet):
# ...
CHOICES = {
('exact', 'exact'), ('not_exact', 'not_exact')
}
type_of_search = django_filters.ChoiceFilter(label="Exact match?", choices=CHOICES, method="filter_instruments")
def filter_instruments(self, queryset, name, value):
if value == 'exact':
return queryset.??
elif value == 'not_exact':
return queryset.??
I know that the query I want is something like:
Work.objects.filter(instrumentations__name='violin').filter(instrumentations__name='viola').filter(instrumentations__name='horn')
I just don't know how to 'translate' it into the django_filters language.
Update 2: 'exact' query using QuerySet.annotate
Thanks to this question, I think this is the query I'm looking for:
from django.db.models import Count
instrument_list = ['...'] # How do I grab them from the form?
instruments_query = Work.objects.annotate(count=Count('instrumentations__name')).filter(count=len(instrument_list))
for instrument in instrument_list:
instruments_query = instruments_query.filter(instrumentations__name=instrument_list)
I feel I'm close, I just don't know how to integrate this with django_filters.
Update 3: WorkFilter that returns empty if the search is exact
class WorkFilter(django_filters.FilterSet):
genre = django_filters.ModelChoiceFilter(
queryset=Genre.objects.all(),
label="Filter by genre")
instrument = django_filters.ModelMultipleChoiceFilter(
field_name="instrumentation__instrument",
queryset=Instrument.objects.all(),
label="Filter by instrument")
CHOICES = {
('exact', 'exact'), ('not_exact', 'not_exact')
}
type_of_search = django_filters.ChoiceFilter(label="Exact match?", choices=CHOICES, method="filter_instruments")
def filter_instruments(self, queryset, name, value):
instrument_list = self.data.getlist('instrumentation__instrument')
if value == 'exact':
queryset = queryset.annotate(count=Count('instrumentations__name')).filter(count=len(instrument_list))
for instrument in instrument_list:
queryset = queryset.filter(instrumentations__name=instrument)
elif value == 'not_exact':
pass # queryset = ...
return queryset
class Meta:
model = Work
fields = ['genre', 'title', 'instrument', 'instrumentation']
You can grab instrument_list with self.data.getlist('instrument').
This is how you would use instrument_list for the 'exact' query:
type_of_search = django_filters.ChoiceFilter(label="Exact match?", choices=CHOICES, method=lambda queryset, name, value: queryset)
instrument = django_filters.ModelMultipleChoiceFilter(
field_name="instrumentation__instrument",
queryset=Instrument.objects.all(),
label="Filter by instrument",
method="filter_instruments")
def filter_instruments(self, queryset, name, value):
if not value:
return queryset
instrument_list = self.data.getlist('instrument') # [v.pk for v in value]
type_of_search = self.data.get('type_of_search')
if type_of_search == 'exact':
queryset = queryset.annotate(count=Count('instrumentations')).filter(count=len(instrument_list))
for instrument in instrument_list:
queryset = queryset.filter(instrumentations__pk=instrument)
else:
queryset = queryset.filter(instrumentations__pk__in=instrument_list).distinct()
return queryset
I need to make a selector with genders (male and female) with the respectives counts of each type.
For example, if I have 4 males and 8 females in my DB, I need a select tags with options
"Select gender"
"Male (4)"
"Female (8)"
In my Form class I have
gender = forms.ModelChoiceField(
queryset=Gender.objects.all().annotate(counter=Count('user')),
required=False,
label="Gender"
)
And I don't know how to render this select element. If I use {{ form.gender }} I can't even display the options. I get Error binding parameter 0 - probably unsupported type. It could be an SQLite issue? I will use PostgreSQL as my DB anyway.
Any suggestions?
EDIT: I need something like this, with almost 10 form fields and a variable number of options in each case
I would do it this way. I tried this and it works fine. Modify it for your needs and it should work fine as well. I am just modifying the widget for gender field.
class testform(forms.ModelForm):
class Meta:
model = names
fields = ['name', 'gender']
male = 'male'+str(names.objects.filter(gender='m').count())
female = 'female'+str(names.objects.filter(gender='f').count())
choices = ((male, male),(female,female))
gender = forms.CharField(widget=forms.Select(choices=choices))
You can override label_from_instance method of ModelChoiceField:
class GenderModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.name + ' ({})'.format(obj.counter)
And use this custom field in your form:
gender = GenderModelChoiceField(
queryset=Gender.objects.all().annotate(counter=Count('user')),
required=False,
label="Gender"
)
I have three models: Business, Offers and OfferPlan:
Business:
class Business(models.Model):
name_of_business = models.CharField(max_length=255)
Offers:
class Offers(models.Model):
business = models.ForeignKey(Business, related_name="business_offer",
on_delete=models.CASCADE)
title = models.CharField(max_length=255)
subtext = models.CharField(max_length=255)
OfferPlan:
class OfferPlan(models.Model):
WEEKDAYS = [
(1, _("Monday")),
(2, _("Tuesday")),
(3, _("Wednesday")),
(4, _("Thursday")),
(5, _("Friday")),
(6, _("Saturday")),
(7, _("Sunday")),
]
offer = models.ForeignKey(Offers, related_name="business_offer_plan",
on_delete=models.CASCADE)
weekday = models.IntegerField(
choices=WEEKDAYS,
)
from_hour = models.TimeField()
to_hour = models.TimeField()
I have a ListView which search for businesses open based on different params such as city, category etc. I also want to now search by weekday, say which business is open on Monday will be displayed and which are not wont be displayed on that day. Weekday information is stored in OfferPlan and there could be multiple timings for the offers that day in OfferPlan table, but I want to query (filter, exclude) the businesses who has even a single entry on that weekday number.
Here is my ListView:
class SearchListView(ListView):
template_name = 'search/search.html'
model = Business
def get_queryset(self):
# queryset = Business.objects.filter(business_address__city=AppLocations.objects.first().city)
if 'city' in self.request.GET:
queryset = Business.objects.filter(business_address__city=self.request.GET.get('city'))
if 'category' in self.request.GET:
queryset = queryset.filter(category__code=self.request.GET.get('category'))
# if 'date' not in self.request.GET:
# queryset = B
raise
return queryset
How could this be possible? Also looked into https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/ but not able to figure out.
Thanks
Update 1
After researching more in the web, I figured out this is how it could be achieved, but need to know for sure from other Django enthusiasts here that it is right.
queryset.filter(business_offer__business_offer_plan__weekday=1).annotate(count_entry=Count('business_offer__business_offer_plan__weekday')).filter(count_entry__gt=1)
Solution
Jefferson's solution was tagged as right answer as it provided more insights, about which query is fast and what wrong was with my previous update, so here is the proper solution to which we both agreed:
queryset.filter(business_offer__business_offer_plan__weekday=1).annotate(count_entry=Count('business_offer__business_offer_plan__weekday')).filter(count_entry__gte=1)
def get_query(weekday):
businesses = Business.objects.filter(business_offer__in=Offers.objects.filter(
business_offer_plan__in=OfferPlan.objects.filter(weekday=weekday))).distinct()
return businesses
There's a heavy query, but it works.
There's no conditional expression here - and your annotation is much too complicated. You just need an additional filter.
queryset.filter(business_offer__business_offer_plan__weekday=self.request.GET['weekday'])
Localhost Screenshot
I have following requirement:
There are exercises and there are ratings
An exercise can have multiple ratings
My goal is to add ratings to the exercises dynamically i.e. I have created all the exercises before hand and rating to a particular exercise I should be able add afterwards calling some function. When I hit 'save_rating' view I get the error "Cannot assign "[]": "Rating.exercise" must be a "Exercise" instance."
What am I doing wrong?
My models.py looks like following
class Exercise(models.Model):
#Field for storing exercise type
EXERCISE_TYPE_CHOICES = (
('BS', 'Best stretch'),
('BR', 'Butterfly reverse'),
('SR', 'Squat row'),
('PL', 'Plank'),
('PU', 'Push up'),
('SP', 'Side plank'),
('SQ', 'Squat'),
)
exercise_type = models.CharField(max_length=5,choices=EXERCISE_TYPE_CHOICES)
#Field for storing intensity level
INTENSITY_LEVEL_CHOICES = (
(1, 'Really simple'),
(2, 'Rather Simple'),
(3, 'Simple'),
(4, 'Okay'),
(5, 'Difficult'),
(6, 'Rather Difficult'),
(7, 'Really Difficult'),
)
intensity_level = models.IntegerField(choices=INTENSITY_LEVEL_CHOICES)
#Field for storing video url for a particular exercise
video_url = models.URLField()
#Field for storing description of the exercise
description = models.CharField(max_length=500)
class Rating(models.Model):
#Field for storing exercise type
exercise = models.ForeignKey(Exercise, related_name='ratings', blank=True, null=True)
#Field for storing rating
RATING_CHOICES = (
('H', 'Happy'),
('N', 'Neutral'),
('S', 'Sad'),
)
value = models.CharField(max_length=1,choices=RATING_CHOICES)
I have defined my serializer like following:
class RatingSerializer(serializers.Serializer):
class Meta:
model = Rating
fields = ('value')
class ExerciseSerializer(serializers.Serializer):
pk = serializers.IntegerField(read_only=True)
exercise_type = serializers.CharField(required=True, allow_blank=False)
intensity_level = serializers.IntegerField(required=True)
video_url = serializers.URLField(required=True)
description = serializers.CharField(required=True, allow_blank=False)
ratings = RatingSerializer(many=True, read_only=True)
My views:
def exercise_list(request):
"""
List all exercises.
"""
if request.method == 'GET':
exercises = Exercise.objects.filter(exercise_type='BS', intensity_level=1)
serializer = ExerciseSerializer(exercises, many=True)
return JSONResponse(serializer.data)
def save_rating(request):
"""
Save a rating for a specific exercise.
"""
#Get a specific exercise for which you want to save the rating
specificExercise = Exercise.objects.filter(exercise_type='BS' , intensity_level=1)
#Create a rating and pass the specific exercise reference to it
Rating.objects.create(exercise = specificExercise, value='H')
#serializer = ExerciseSerializer(rating, many=True)
serializer = ExerciseSerializer(instance=specificExercise)
return JSONResponse(serializer.data)
In your function save_rating, you are having specificExercise as a queryset not one Exercise instance, so when you do:
Rating.objects.create(exercise=specificExercise, value='H')
You try to assign a queryset to your exercise field, which of course doesn't work.
Simple fix would be using get instead of filter so you got one instance. But you also have to make sure the get query doesn't throw DoesNotExist exception, so a simple try except would do.
Edit:
def save_rating(request):
"""
Save a rating for a specific exercise.
"""
# Get a specific exercise for which you want to save the rating
try:
specificExercise = Exercise.objects.get(exercise_type='BS',
intensity_level=1)
# Create a rating and pass the specific exercise reference to it
Rating.objects.create(exercise = specificExercise, value='H')
# serializer = ExerciseSerializer(rating, many=True)
serializer = ExerciseSerializer(instance=specificExercise)
return JSONResponse(serializer.data)
except Exercise.DoesNotExist:
# TODO: you need to return some error indication that there's no such exercise
return None
Please read django doc about making queries.
I made a model something like this:
class Enduser(models.Model):
user_type = models.CharField(max_length = 10)
Now I want user_type to have only one of the given values, say any one from ['master', 'experienced', 'noob']
Can I do this with Django?
Also, how can I display a list of radio buttons or drop-down list/select menu to chose one of these values?
You can take advantage of the choices attribute for CharField:
class Enduser(models.Model):
CHOICES = (
(u'1',u'master'),
(u'2',u'experienced'),
(u'3',u'noob'),
)
user_type = models.CharField(max_length = 2, choices=CHOICES)
This will save values 1,2 or 3 in the db and when retrieved the object, it will map it to master, experienced or noob. Take a look at the docs for more info.
Hope this helps!
Use model field choices:
CHOICES = (
('foo', 'Do bar?'),
...
)
class Enduser(models.Model):
user_type = models.CharField(max_length = 10, choices=CHOICES)