Django Users' Preferences - django

I'd like to know what is the best way to store users' preferences in Django.
Let's say I have three choices users can select.
Based on their selection I want to customize certain templates.
Is it better to save each choice/preference as BooleanField() or as a tuple of choices?
Boolean:
subscription_newsletter = model.BooleanField()
subscription_posts = model.BooleanField()
subscription_promotions = model.BooleanField()
Tuple:
SUBSCRIPTION_CHOICES = (
("newsletter","Newsletter"),
("posts", "Posts"),
("promotions", "Promotions"),
)

It depends, whether you want them to be able to choose just one option (then tuples) or many (then booleans).

Related

How can i make people selected 2 choices between 3 options?

I want users to choice 2 selection of my checkbox how can i do that by using Django?
I ve tried that
forms.py
class KaydolForm(forms.ModelForm):
secim = (('Bk','banka kartı'),('kk','Kredi Kartı'),('cek', 'çek'))
secims=forms.ChoiceField(choices=secim, widget=forms.RadioSelect)
but i can choose only one of them
https://docs.djangoproject.com/en/3.1/ref/forms/fields/#multiplechoicefield
Read this, in your form it would be like this:
class KaydolForm(forms.ModelForm):
choices = (
('Bk', 'banka kart1),
('kk', 'Kredi'),
('cek', 'cek')
)
secims = forms.MultipleChoiceField(choices=choices)
You should use a MultipleChoiceField. On this field you can select multiple options.
Then you should also use a widget (representation on webpage) that accepts multiple choices. You could use CheckboxSelectMultiple or SelectMultiple
So change your code to:
class KaydolForm(forms.ModelForm):
choices_list = (('Bk','banka kartı'),('kk','Kredi Kartı'),('cek', 'çek'))
choice_field = forms.MultipleChoiceField(choices=choices_list, widget=forms.SelectMultiple)
The user could now however check one, two or three options. You must write a own validator to check, if exactly two are checked. For more detail see here

How can I make a choice field with steps in Django admin

I'm trying to make something like the image below. Let's say that I have 3 multiple choice fields like the following. If I choose bags from choices_first, I want choices_for_bags to show up as the next choice step.
The below image is one of the fields for Django default user model. It's for another purpose. I'm looking for something like that. As I choose something on the left, I want something to show up on the right based on the choice on the left. Does Django admin provide anything like that as default or is there any library for that?
choices_first = (
('clothing', 'Clothing'),
('bags', 'Bags'),
)
choices_for_clothing = (
('tops', 'Tops'),
('bottoms', 'Bottoms'),
)
choices_for_bags = (
('handbags', 'Handbags'),
('backpacks', 'Backpacks'),
)
As far as I know django-smart-selects provide ChainedManyToManyField option which should be similar to User Permissions scenario since its ManyToMany field, but I'm not sure if it will work as you need.

Django MultiSelectField with multiple fields per choice

I'm using MultiSelectField in my form, which allows the user to select multiple choices:
models.py
physical_limits = MultiSelectField('Physical Limitations', choices=PHYSICAL_LIMIT, max_length=255)
screenshot link
However, I would like to add few additional fields per choice, e.g. min value, max value, units, etc (for the user to fill in, for each choice he makes).
For example, if the user selects option (2), which is "Solid", he will then be able to fill in additional corresponding "sub-fields" for this selection.
In some way, I feel like I'm looking for a different field type, which acts more like a table or array, for the user to fill. I couldn't find such a thing though..
"Vision"
Can you please guide me how to achieve that goal?
Thanks ahead,
Shahar

Django distinct foreign keys for use in another model

class Log:
project = ForeignKey(Project)
msg = CharField(...)
date = DateField(...)
I want to select the four most recent Log entries where each Log entry must have a unique project foreign key. I've tried the solutions on google search but none of them works and the django documentation isn't that very good for lookup..
I tried:
id_list = Log.objects.order_by('-date').values_list('project_id').distinct()[:4]
entries = Log.objects.filter(id__in=id_list)
id_list is empty unless I remove the order_by() but then it's not in the correct order.
entries = Log.objects.filter(id__in=id_list)
The objects in entries is not in the same order as in id_list because when you use Mysql function IN() it will not sort the result by the input order ... How to do it in django?
It looks like it is impossible to achieve what you want with django orm. Documentation states that is not possible to use order_by along with distinct.
However there might be another way to solve it. Maybe you could select Project objects, and annotate them with latest log entries.
Here's a single-query solution (but it will probably be too slow):
Log.objects.filter(project__log__date__gte=F('date')).annotate(c=Count('project__log')).filter(c__lte=4).order_by('project', 'c')
I think that Skirmantas is right and you have to do it in a more complex way:
from django.db.models import Max
projects = Project.objects.annotate(last_logged=Max('log__date')).order_by('-last_logged')[:4]
log_entries = [proj.log_set.order_by('-date')[0] for proj in projects]

django aggregate aggregated fields?

I have a model called Item, with m2m relation to User ("owner").
For each item, I need to count users who own it. That's easy enough with annotate()
But then I need to calculate ratio between owners of specific gender and total owner count for each item. For example if, 2 males own the item out of 5 users, the ratio is 0.4.
What's the best way to do that?
To do this with the ORM, you need conditional aggregates, which aren't supported in Django. http://www.voteruniverse.com/Members/jlantz/blog/conditional-aggregates-in-django proposes a hacky solution that might work.
If you don't need to sort by the ratio, then you can make two calls to annotate, and then compute the ratio in Python. Something like:
items = Item.objects.annotate(ucount=Count('users')).annotate(ccount=CountIf(<condition>))
for item in items:
item.ratio = item.ucount / item.ccount
If you don't want to do that, I'd recommend using the extra() method and some custom sql to get the extra info you want. Documentation for that method is on the Django Queryset API documentation page.
Just on top of my head, something like the following could work. Iterate on it to get your perfect solution if you wish:
items = Item.objects.annotate(Count('users'))
for item in items:
total = item.users__count
num_males = item.users.filter(gender='M').count()
num_females = item.users.filter(gender='F').count()