0 value in Django PositiveIntegerField? - python

Can a field of type models.PositiveIntegerField contain a 0 value? I'm doing something like:
points = models.PositiveIntegerField()
Thanks,
I know I should try it myself, but I haven't a Django environment here.

Yes, it can. It is debatable whether it should--there is a longstanding bug report: http://code.djangoproject.com/ticket/7609

For those looking to exclude the 0, it's easy to write a validator for that.
def validate_nonzero(value):
if value == 0:
raise ValidationError(
_('Quantity %(value)s is not allowed'),
params={'value': value},
)
and then use it as such
fill_qty = models.PositiveIntegerField(
default=0,
validators=[MaxValueValidator(1000000), validate_nonzero]
)

Yes.
The model field reference says so. For completeness, also quoted here:
PositiveIntegerField
class PositiveIntegerField([**options])
Like an IntegerField, but must be either positive or zero (0). The value 0 is accepted for backward compatibility reasons.

Well by the definition of a Positive Integer, it shouldn't accept a zero value, but django actually considers it in the sense of none-negative number which is zero inclusive. So, Yes it can accept a zero value

Yes, "PositiveIntegerField" can contain "0" value.
For example, I defined the model "Point" as shown below:
# "myapp/models.py"
from django.db import models
class Point(models.Model):
points = models.PositiveIntegerField()
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Now, I opened "db.sqlite3" then as you can see, "CHECK("points" >= 0)" is set to "points" field which means "PositiveIntegerField" can contain "0" value:

Related

How to set default values into an Array Field Django?

I would like to know how to set default values into a Django Array Field Model.
I have a TextChoices model named "GameType" :
class GameType(models.TextChoices):
'''
Enumeration of all different game types
'''
EVIL = 'evil', 'evil'
SOLOCOOP = 'solo', 'solo'
MULTI = 'multi', 'multi'
And in my Item model, I can choose in each mode my item is available. Then I have these lines :
game_types = ArrayField(
models.CharField(
default=GameType.SOLOCOOP,
max_length=40,
choices=GameType.choices
), default=default_item_game_types, null=False, blank=False)
Two things :
The first default key "GameType.SOLOCOOP" doesn't work
The default list doesn't work too
Here is my "default_item_game_types" function :
def default_item_game_types():
'''Default callable to avoid errors
'''
return list(GameType)
And in my CMS, I don't have my default values :
Screenshot of my Game types field
I tried many things and searched many solutions but nothing matched in my case.
Is there any response to fix my issues ?
Thanks for your time
Regards,
Steven
1: You need to set it like
self.SOLOCOOP = 'solo'
Can do this in a custom method or init if you know the defaults for it, that would be much easier than calling the custom method.
2:The default values are based on the Charfield as it is an Array of fields in some sense.
EDITED:
Just do the str_value then or better just do the key value for solar as you're already using it as choices in the parameter below.

Django conditional annotation without filtering

I have a Student model and an Entry model. Each Entry has a foreign key to a Student, a year-stamp, and two numeric values (value1 and value2). I am overriding the get_queryset() method in the StudentAdmin class, and using the Django ORM, I want to annotate a field that we'll call "specialvalue".
Students have at most one Entry for each year, but they might have none, and they might have an Entry for years in the future. The value of "specialvalue" will be equal to Entry__value1 minus Entry__value2 for the Entry for the current year. If the Student has no Entry for the current year, then specialvalue will just be equal to None, and these Students will NOT be removed from the queryset.
How can I do this? At first I tried splitting the queryset into two:
queryset_1 = queryset.filter(entry__year=THIS_YEAR).annotate(specialvalue=...)
queryset_2 = queryset.exclude(entry__year=THIS_YEAR).annotate(specialvalue=Value(None))
and then annotating them separately and merging them with the | pipe operator, but unfortunately this results in the wrong results due to a known bug in Django's ORM.
Thank you!
I think, using Django conditional expression will be applicable solution in your case. Read about Case expression for more information (https://docs.djangoproject.com/en/1.11/ref/models/conditional-expressions/#case). All you need is to check whether an entry is related to a CURRENT_YEAR or not.
Case() accepts any number of When() objects as individual arguments. Other options are provided using keyword arguments. If none of the conditions evaluate to TRUE, then the expression given with the default keyword argument is returned. If a default argument isn’t provided, None is used.
I didn't test this solution but I think it should work:
from django.db.models import Case, When, F, IntegerField
queryset = queryset.annotate(
specialvalue=Case(
When(entry__year=THIS_YEAR,
then=F('entry__value1') - F('entry__value2')
), output_field=IntegerField()
)
).values_list('specialvalue')

Does 'default=...' in Django model fields set 'blank=True' by default?

I have a question for the Django model field when applying the default setting. My problem is as follows:
# Model description
class aa(models.Model):
a = models.FloatField(default=1)
b = models.FloatField()
When inserting an entry into the database, I apply the following functions to do the validation without any error:
data = {'b': 1.1} # Just for demo...
p = aa(**data)
p.full_clean()
p.save()
Here is the problem, is the case that when I set the default value for a field, the blank is automatically set to True?
P.S. I know what are the differences between null and blank, I just want to figure out the issues related to the default.
If you put default on a model field, actually it is not setting blank = True . When you initialize a Model like
instance = ModelClass(**field_data)
django will check for all fields and if the field value is not there, then it will try checkin default value by calling get_default() method (look for default value) on Field class.
Django model fields default to required unless you specify blank=True and/or null=True. In your example, the model validates because you have defaulted a to 1 and set b to 1.1. Neither field is blank, so you're not encountering a situation that hits the question you're asking.
Try changing data = {'b': 1.1} to data = {'a': 1.1} and see what happens - you should get a field validation error.
Yes. Django always do that. If you don't need that feature simple make it set blank = False

Altered Django model. I provided a one-off default = datetime.date for DateField. Found that it's invalid. Removed the field and still can't migrate

Hi here's the specific line that I added in models.py
billingMonth2 = models.DateTimeField()
This is what happened in makemigrations, I figured I added a non nullable field so I tried to define a default value:
You are trying to add a non-nullable field 'billingMonth' to bills
without a default; we can't do that (the database needs something to populate
existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do
e.g. timezone.now()
>>> datetime.date
Migrations for 'bills':
0007_auto_20160609_1400.py:
- Change Meta options on bills
- Add field billingMonth to bills
I found out that datetime.date was invalid and came out with an error
....File "/home/jrbenriquez/Envs/env1/local/lib/python2.7/site-packages/django/db/backends/base/schema.py", line 197, in effective_default
default = field.get_default()
File "/home/jrbenriquez/Envs/env1/local/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 797, in get_default
return self.default()
TypeError: Required argument 'year' (pos 1) not found
So I just removed the billingMonth2 field hoping it would go back to normal and also setting a default value as
`billingMonth2 = models.DateTimeField(default='Test',null=True,blank=True)`
Both still gives the same error.
It seems to me I have changed something within the meta of the model in some other file or in the database and that I have to delete the default value "datetime.date" somewhere
I hope someone could help me here. Thanks!
UPDATE:
Here's 0007_auto20160609_1400.py
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-06-09 14:00
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.datetime_safe
class Migration(migrations.Migration):
dependencies = [
('bills', '0006_bills_duedate'),
]
operations = [
migrations.AlterModelOptions(
name='bills',
options={'ordering': ('-id', '-status'), 'verbose_name_plural': 'Bills'},
),
migrations.AddField(
model_name='bills',
name='billingMonth',
field=models.DateField(default=django.utils.datetime_safe.date),
preserve_default=False,
),
]
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
>>> datetime.date
I guess it is asking for the return value of the method, not the method itself. So its datetime.date() with the () at the end.
Also, in your model's field declaration, you can set the current date as a default, if that's what you tried to do
billingMonth2 = models.DateTimeField(default=datetime.date, null=True, blank=True)
There you give it the method itself, without the (), so that the time is taken when a new row is created, not only when the model is first defined.
During Makemigrations use: datetime.date.today() for fill DB or you'll get "TypeError: function missing required argument 'year' (pos 1)".
Checkout this image:
Try the following. Note: You will lose all the data in your DB!
Delete all the migrations in your app (say: 001_initial.py)
Delete the database (for me db.sqlite3,it's django provided one)
(If have external one, drop the db and create new one)
Atlast run : python manage.py makemigrations
Python manage.py migrate
After that you can run normally.
Hope it will be helpful.
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
datetime.date
or
timezone.now()
or
timezone.now

Django models - field dependency

How can I have field dependency?
Case 1: If boolean field call_me is set, then telephone must be set, else it should be blank
Case 2: If many to many field category (with values sale, rent) has one of the values as sale, then price_sale must be set, else it should be blank
For Case 1, you can validate that easily in the model's clean method:
from django.core.exceptions import ValidationError
class MyModel(models.Model):
...
def clean(self):
if self.call_me and not self.telephone.strip():
raise ValidationError('Telephone is required')
For Case 2, M2M relationships are not added until after the model is saved, so using clean on your model won't work in this scenario. However, you can do this from the clean method of any ModelForm you use to edit this, be it in the admin or your own view.
However, having category as a M2M when the only possible values are "sale" and "rent", is poor design. Even then, "sale" and "rent" are mutually exclusive, so an M2M is inappropriate anyways (your model won't be experiencing both a "sale" and a "rent" at the same time ever).
As a result, it would be a better idea to have category be a CharField with choices consisting of "sale" and "rent". If you do it that way, you can then use your model's clean method in the same way as Case 1 for this as well.
Case 1:
Don't do it like that, have a different table for telephone numbers and have a ForeignKey from the Person (I'm assuming it's a person) to the the telephone number. If you have more than one telephone number per person, do it the other way around, otherwise consider using a OneToOne.
Obviously you'll want the ForeignKey to be nullable. That way, the only way to have a telephone number is if the person provided one.
Case 2:
I don't understand your database design here, so I can't answer. You'll have to explain more - why do you need a ManyToMany here?

Categories