I would like to display priority information in a drop down. Currently i am using a integer field to store the priority, but i would like to display high/medium/low instead of letting user type in a priority.
A way to approximate this is to use a Priority database which stores 3 elements, 1:high, 2:medium, 3:low, but it seems like an overkill.
Any easier way would be much appreciated!
Jason
You can specify choices for a field http://www.djangoproject.com/documentation/models/choices/.
PRIORITY_CHOICES = ((1, 'High'),
(2, 'Medium'),
(3, 'Low'))
class MyModel(models.Model):
priority = models.IntegerField(choices=PRIORITY_CHOICES)
You could write your model like this:
from django.db import models
class Priority(models.Model):
PRIORITY_LOW = 3
PRIORITY_MEDIUM = 2
PRIORITY_HIGH = 1
PRIORITY_CHOICES = (
(PRIORITY_LOW, 'low'),
(PRIORITY_MEDIUM, 'medium'),
(PRIORITY_HIGH, 'high'),
)
priority = models.IntegerField(choices=PRIORITY_CHOICES)
You read more from the documentation
You should be able to add choices to the model element
So:
class myModel(models.Model):
mydata = models.CharField(max_length=4, choices= ((u'H', u'High',), (u'M', u'Medium'), (u'L', u'Low')))
Would store H,M,L in the DB, but present High, Medium, Low. Admin defaults fields with the choices attribute to a drop down selector
Related
I wanted to know if there is a way to insert a search bar in the Django choices, that is instead of manually searching the various choices if it is possible to use a filter bar to search for our choice in Django Admin - Models.
Well I think django-filter library provide you with maybe good facilities for this purpose, I have briefly given you some examples from it's documentation below:
ChoiceFilter
This filter matches values in its choices argument. The choices must be explicitly passed when the filter is declared on the FilterSet.
class User(models.Model):
username = models.CharField(max_length=255)
first_name = SubCharField(max_length=100)
last_name = SubSubCharField(max_length=100)
status = models.IntegerField(choices=STATUS_CHOICES, default=0)
STATUS_CHOICES = (
(0, 'Regular'),
(1, 'Manager'),
(2, 'Admin'),
)
class F(FilterSet):
status = ChoiceFilter(choices=STATUS_CHOICES)
class Meta:
model = User
fields = ['status']
TypedChoiceFilter
The same as ChoiceFilter with the added possibility to convert value to match against. This could be done by using coerce parameter. An example use-case is limiting boolean choices to match against so only some predefined strings could be used as input of a boolean filter:
import django_filters
from distutils.util import strtobool
BOOLEAN_CHOICES = (('false', 'False'), ('true', 'True'),)
class YourFilterSet(django_filters.FilterSet):
...
flag = django_filters.TypedChoiceFilter(choices=BOOLEAN_CHOICES,
coerce=strtobool)
MultipleChoiceFilter
The same as ChoiceFilter except the user can select multiple choices and the filter will form the OR of these choices by default to match items. The filter will form the AND of the selected choices when the conjoined=True argument is passed to this class.
Multiple choices are represented in the query string by reusing the same key with different values (e.g. ‘’?status=Regular&status=Admin’’).
TypedMultipleChoiceFilter
Like MultipleChoiceFilter, but in addition accepts the coerce parameter, as in TypedChoiceFilter.
See also:
django-filter [Docs]
django-filter [Github]
I'm trying to optimize the fired queries of an API. I have four models namely User, Content, Rating, and UserRating with some relations to each other. I want the respective API returns all of the existing contents alongside their rating count as well as the score given by a specific user to that.
I used to do something like this: Content.objects.all() as a queryset, but I realized that in the case of having a huge amount of data tons of queries will be fired. So I've done some efforts to optimize the fired queries using select_related() and prefetch_related(). However, I'm dealing with an extra python searching, that I hope to remove that, using a controlled prefetch_related() — applying a filter just for a specific prefetch in a nested prefetch and select.
Here are my models:
from django.db import models
from django.conf import settings
class Content(models.Model):
title = models.CharField(max_length=50)
class Rating(models.Model):
count = models.PositiveBigIntegerField(default=0)
content = models.OneToOneField(Content, on_delete=models.CASCADE)
class UserRating(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE
)
score = models.PositiveSmallIntegerField()
rating = models.ForeignKey(
Rating, related_name="user_ratings", on_delete=models.CASCADE
)
class Meta:
unique_together = ["user", "rating"]
Here's what I've done so far:
contents = (
Content.objects.select_related("rating")
.prefetch_related("rating__user_ratings")
.prefetch_related("rating__user_ratings__user")
)
for c in contents: # serializer like
user_rating = c.rating.user_ratings.all()
for u in user_rating: # how to remove this dummy search?
if u.user_id == 1:
print(u.score)
Queries:
(1) SELECT "bitpin_content"."id", "bitpin_content"."title", "bitpin_rating"."id", "bitpin_rating"."count", "bitpin_rating"."content_id" FROM "bitpin_content" LEFT OUTER JOIN "bitpin_rating" ON ("bitpin_content"."id" = "bitpin_rating"."content_id"); args=(); alias=default
(2) SELECT "bitpin_userrating"."id", "bitpin_userrating"."user_id", "bitpin_userrating"."score", "bitpin_userrating"."rating_id" FROM "bitpin_userrating" WHERE "bitpin_userrating"."rating_id" IN (1, 2); args=(1, 2); alias=default
(3) SELECT "users_user"."id", "users_user"."password", "users_user"."last_login", "users_user"."is_superuser", "users_user"."first_name", "users_user"."last_name", "users_user"."email", "users_user"."is_staff", "users_user"."is_active", "users_user"."date_joined", "users_user"."user_name" FROM "users_user" WHERE "users_user"."id" IN (1, 4); args=(1, 4); alias=default
As you can see on the above fired queries I've only three queries rather than too many queries which were happening in the past. However, I guess I can remove the python searching (the second for loop) using a filter on my latest query — users_user"."id" IN (1,) instead. According to this post and my efforts, I couldn't apply a .filter(rating__user_ratings__user_id=1) on the third query. Actually, I couldn't match my problem using Prefetch(..., queryset=...) instance given in this answer.
I think you are looking for Prefetch object:
https://docs.djangoproject.com/en/4.0/ref/models/querysets/#prefetch-objects
Try this:
from django.db.models import Prefetch
contents = Content.objects.select_related("rating").prefetch_related(
Prefetch(
"rating__user_ratings",
queryset=UserRating.objects.filter(user__id=1),
to_attr="user_rating_number_1",
)
)
for c in contents: # serializer like
print(c.rating.user_rating_number_1[0].score)
I have the following model used to store a bidirectional relationship between two users. The records are always inserted where the smaller user id is user_a while the larger user id is user_b.
Is there a way to retrieve all records belonging to a reference user and the correct value of the status (apply negative transformation to relationship_type if user_a) based on whether the reference user id is larger or smaller than the other user id?
Perhaps two separate queries, one where reference user = user_a and another where reference user = user_b, followed by a join?
class Relationship(models.Model):
RELATIONSHIP_CHOICES = (
(0, 'Blocked'),
(1, 'Allowed'),
(-2, 'Pending_A'),
(2, 'Pending_B'),
(-3, 'Blocked_A'),
(3, 'Blocked_B'),
)
user_a = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name='user_a',null=True)
user_b = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name='user_b',null=True)
relationship_type = models.SmallIntegerField(choices=RELATIONSHIP_CHOICES, default=0)
A SQL query of what I'm trying to achieve:
(SELECT user_b as user_select, -relationship_type as type_select WHERE user_a='reference_user') UNION (SELECT user_a as user_select, relationship_type as type_select WHERE user_b='reference_user')
Given you have the id of the user user_id, you can filter with:
from django.db.models import Q
Relationship.objects.filter(Q(user_a_id=user_id) | Q(user_b_id=user_id))
If you have a CustomUser object user, it is almost the same:
from django.db.models import Q
Relationship.objects.filter(Q(user_a=user) | Q(user_b=user))
If you are looking to obtain Relationships with a given type, we can do the following:
from django.db.models import Q
rel_type = 2 # example rel_type
Relationship.objects.filter(
Q(user_a=user, relationship_type=rel_type) |
Q(user_b=user, relationship_type=-rel_type)
)
Here we thus retrieve Relationship objects with user_a the given user and relationship_type=2, or Relationship objects with user_b the given user, and relationship_type=-2.
We could annotate the querysets, and then take the union, like:
qs1 = Relationship.objects.filter(
user_a=user, relationship_type=rel_type
).annotate(
user_select=F('user_b'),
rel_type=F('relationship_type')
)
qs2 = Relationship.objects.filter(
user_a=user, relationship_type=rel_type
).annotate(
user_select=F('user_a'),
rel_type=-F('relationship_type')
)
qs = qs1.union(qs2)
Although I do not know if that is a good idea: the annotations are not "writable" (so you can not update these).
It might be better to implement some sort of "proxy object" that can swap user_a and user_b, and negate the relationship type, and thus is able to act as if it is a real Relationship object.
As you said, id in user_a is always smaller than user_b. So if you query with user_b=user then you should always get the references where user_id in the reference is always higher than other user_id. So I think you can use following querysets:
user = CustomUser.objects.get(id=1)
user_a_references = Relationship.objects.filter(user_a=user)
user_b_references = Relationship.objects.filter(user_b=user)
all_relation_ships = user_a_reference.union(user_b_references)
all:
What is the correct Model fieldtype to use with a CheckboxSelectMultiple widget for static data? I am receiving validation errors and feel I'm missing something simple.
The app is a simple Django 1.6 app in which a Campground object can have multiple eligible_days (e.g. Site #123 may be available on Monday & Tuesday, while Site #456 is available on Weds-Friday).
Because it's static data and I've ready that a ManyToManyField has unnecessary DB overhead, I'm trying to do this with choices defined inside the model, but when I try to save I get the validation error Select a valid choice. [u'5', u'6'] is not one of the available choices. every time.
Q1: Do I have to override/subclass a field to support this?
Q2: Do I need a custom validation method to support this?
Q3: Am I making things unnecessarily hard on myself by avoiding ManyToManyField?
Thank you for your help!
/m
models.py
class CampgroundQuery(models.Model):
SUN = 0
MON = 1
TUE = 2
WED = 3
THU = 4
FRI = 5
SAT = 6
DAYS_OF_WEEK_CHOICES = (
(SUN, 'Sunday'),
(MON, 'Monday'),
(TUE, 'Tuesday'),
(WED, 'Wednesday'),
(THU, 'Thursday'),
(FRI, 'Friday'),
(SAT, 'Saturday'),
)
# loads choices from defined list
eligible_days = models.CharField(max_length=14,choices=DAYS_OF_WEEK_CHOICES,
blank=False, default='Saturday')
campground_id = models.SmallIntegerField()
stay_length = models.SmallIntegerField()
start_date = models.DateField()
end_date = models.DateField()
admin.py
from django.contrib import admin
from searcher.models import CampgroundQuery
from forms import CampgroundQueryAdminForm
class CampgroundQueryAdmin(admin.ModelAdmin):
form = CampgroundQueryAdminForm
admin.site.register(CampgroundQuery, CampgroundQueryAdmin)
forms.py
from django import forms
from django.contrib import admin
from searcher.models import CampgroundQuery
class CampgroundQueryAdminForm(forms.ModelForm):
class Meta:
model = CampgroundQuery
widgets = {
'eligible_days': forms.widgets.CheckboxSelectMultiple
}
I know this is an old question, but for those who wish to avoid using a ManyToManyField, there is a package to do this, django-multiselectfield, which is quick and easy to implement.
forms.py
from multiselectfield import MultiSelectFormField
class MyForm(forms.ModelForm):
my_field = MultiSelectFormField(choices=MyModel.MY_CHOICES)
models.py
from multiselectfield import MultiSelectField
class MyModel(models.Model):
MY_CHOICES = (
('a', "A good choice"),
...
('f', "A bad choice"),
)
my_field = MultiSelectField(choices=MY_CHOICES, max_length=11)
And that's it! It stores the keys of MY_CHOICES in a comma-separated string. Easy!
A ManyToManyField is the correct choice.
In theory you could create a compact representation, like a string field containing representations like "M,W,Th" or an integer that you'll set and interpret as seven binary bits, but that's all an immense amount of trouble to work with. ManyToManyFields are fine.
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)