I created the following model to understand how to work with Django properties:
from django.db import models
class Person(models.Model):
_first_name = models.CharField(max_length=50, db_column='first_name')
#property
def first_name(self):
"""This is the getter. You can add logic too."""
return self._first_name
#first_name.setter
def first_name(self, fname):
self._first_name = fname
Why do I get the following error when I run the "makemigrations" command. I didn't have to specify default values for fields prior to Django 1.7. Does it have anything to do with my use of the property decorator?
Thanks.
You are trying to add a non-nullable field '_first_name' to person 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...
2) Quit...
It is says that default models.CharField has the attribute blank=False witch means that it can't store an empty string value and it needs a default value in case it needs to store one, default="my default value" witch will be used if it has to store something equivalent to an empty string.
To fix this problem you can do the following
1)Allow empty strings values
You do this by specifying :
_first_name = models.CharField(max_length=50, db_column='first_name', blank=True)
2)Set a default value if it encounters and empty string
You give to him something to use instead of storing an empty string.
You do this by specifying :
_first_name = models.CharField(max_length=50, db_column='first_name', default="My default value")
By default we cannot store a empty string so we use blank=True to allow that.
Try this:
first_name = models.CharField(max_length=50, db_column='first_name',blank=False)
Related
I have a product model like this below:
class Brand(models.Model):
name = models.CharField(primary_key=True, max_length=100)
def __str__(self):
return self.name
class Product(models.Model):
...
brand = models.ForeignKey(Brand, on_delete=models.PROTECT, default='Mercedes')
...
When I am posting a product without the brand field it works and sets the product with brand default value, but when I add a brand field like this brand: "", or send a value which doesn't exist inside Brand table like this: brand: "abc123", it shows me informations:
This field may not be null. and Invalid pk \"abc123\" - object does not exist.. I still want to set the default value in this situations, so if the value is null or does not exist I want to use the default='Mercedes'. How can I do this?
For problem 1). Set null=True on the brand field in the Product model. This will allow null values for that field in the db.
For problem 2). Assuming you want to create the brand instance if it doesn't exist you can use Model.objects.get_or_create().
obj, created = Brand.objects.get_or_create(
other_field='Foo', # optional if other fields have defaults
another_field='Bar', # optional if other fields have defaults
defaults={'name': 'Toyota'}, # the fallback value if object doesn't exist
)
obj is the retrieved or newly created object and created will tell you whether the obj existed or not.
Then use the obj for brand when you create your Product.
If you don't want to create an object, you can just use get() in a try except statement:
from django.core.exceptions import ObjectDoesNotExist
try:
brand = Brand.objects.get(name="Toyota")
product = Product.objects.create(brand=brand)
except ObjectDoesNotExist:
# handle exception
When I define a non nullable field in django it allows me to save a model instance without specifying any value for this non-nullable field. This is not what I would expect. How can I force this to yield an error?
Postgres 9.1
django 2.1
windows
python 3.6
from django.db import models
class Wwtp(models.Model):
name = models.CharField(max_length=100, null=False,
blank=False, unique=True)
short_name = models.CharField(
max_length=10, null=False, blank=False, unique=True)
As expected, I am not allowed to save it with an explicit empty short_name.
mdl.Wwtp.objects.create(name='Wwtp4', short_name=None)
But I am allowed to save an instance of Wwtp without specifying short_name:
mdl.Wwtp.objects.create(name='Wwtp4')
and when I try:
mdl.Wwtp.objects.create()
it gives me
django.db.utils.IntegrityError: duplicate key value violates unique constraint "api_wwtp_short_name_key"
DETAIL: Key (short_name)=() already exists.
Apparently django filled the database with an empty value for short_name while it is not allowed to do so... How can I force the database to not allow this?
You can't with CharField. The empty value is an empty string '', not NULL. You already have blank=False set, so if you clean your model or model forms before saving them, you'll catch that. But it cannot be enforced at the database level.
Note that blank=False, null=False is the default, so you really don't have to specify that.
Also, if you really only want to support PostgreSQL, you could make a custom migration using RunSQL to create your column on the table, manually adding the SQL needed to add the constraint (e.g. using CHECK). See here for how to ensure Django also knows the column was created and doesn't try to add it in the next migration. There's an example here.
[Edit] In Django 2.2, you can add a CheckConstraint in the model's Meta class constraints attribute:
from django.db.models import CheckConstraint, Q
(...)
class Meta:
constraints = [
CheckConstraint(
check=~Q(name=''),
name='name_not_empty'),
CheckConstraint(
check=~Q(short_name=''),
name='short_name_not_empty']
I have a simple model class:
class MyModel(models.Model):
place = models.CharField(max_length=25, verbose_name='Place')
name = models.CharField(max_length=25, verbose_name='Name')
And I'd like to ask you, is there a possibility to automatically set as default value for place field as number of records in table + 1
so for example if there will not be records in table the system automatically change the line to
place = models.CharField(max_length=25, verbose_name='Place', default='1')
Will be thankful for your help,
The default value can be a callable. i.e: you can call a method on the class to compute what you want the value to be.
So you could do:
class MyModel(models.Model):
def compute_default(self):
return <compute default, from query>
place = models.CharField(max_length=25, verbose_name='Place', default=compute_default)
Here's another reference: Result of database query as default value for Django model field?
Another option you might consider is to do this when the object is saved.
See: https://docs.djangoproject.com/en/2.0/ref/models/instances/#what-happens-when-you-save
You could use a signal, or override the .save() method on the object.
And I'd like to ask you, is there a possibility to automatically set as default value for place field as number of records in table + 1
For this part, you dont have to do anything. django does that automatically. It is called "id" field. So in your Model, first record will have a id of 1, second record will have id of 2 and so on.
For other default value, you can use default keyword.
class MyModel(models.Model):
place = models.CharField(max_length=25,verbose_name='Place',default="SomePlace")
name = models.CharField(max_length=25, verbose_name='Name')
I have a simple model which looks like this:
class Group(models.Model):
name = models.CharField(max_length = 100, blank=False)
I would expect this to throw an integrity error, but it does not:
group = Group() # name is an empty string here
group.save()
How can I make sure that the name variable is set to something non-empty? I.e to make the database reject any attempts to save an empty string?
another option that doesn't require you to manually call clean is to use this:
name = models.CharField(max_length=100, blank=False, default=None)
blank will prevent an empty string to be provided in the admin or using a form or serializer (most cases). However as pointed out in the comments, this unfortunately does not prevent things like model.name = "" (manually setting blank string)
default=None will set name to None when using something like group = Group(), thus raising an exception when calling save
From the Django docs in this case, your name will be stored as an empty string, because the null field option is False by default. if you want to define a custom default value, use the default field option.
name = models.CharField(max_length=100, blank=False, default='somevalue')
On this page, you can see that the blank is not database-related.
Update:
You should override the clean function of your model, to have custom validation, so your model def will be:
class Group(models.Model):
name = models.CharField(max_length=100, blank=False)
def clean(self):
from django.core.exceptions import ValidationError
if self.name == '':
raise ValidationError('Empty error message')
Or you can replace ValidationError to something else. Then before you call group.save() call group.full_clean() which will call clean()
Other validation related things are here.
Or you can simply use MinLengthValidator with a 1-char minimum:
from django.core.validators import MinLengthValidator
class Company(BaseModel):
"""Company"""
name = models.CharField(max_length=255,
validators=[MinLengthValidator(1)])
I spent a long time looking for the best solution for this simple (and old) problem, And as of Django 2.2, there is actually a really simple answer, so I'll write it here in case someone still encounters the same problem:
Since Django 2.2, we can define CheckConstraints, so it's easy to define a non-empty string constraint:
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=32)
class Meta:
constraints = [
models.CheckConstraint(check=~models.Q(title=""), name="non_empty_title")
]
Django’s validation system assumes that all fields are required,unless you mention that its ok to leave it blank..
Have you registered the class in Admin ? does it show errors when you leave it blank ??
I want to create a Django model Field (IntegerField) with a default value, and also create a form derived from the model, where the field is optional. If it's not set on the form, then when I save the form, I want the default value saved to the DB.
# model.py
class Invoice(models.Model):
# IntegrityError "Column 'expireDays' cannot be null"
expireDays = models.PositiveSmallIntegerField(default=1)
# expireDays = *null* in DB
expireDays = models.PositiveSmallIntegerField(default=1, blank=True, null=True)
# forms.py
class InvoiceForm(forms.ModelForm):
# leaving this line out gives invalid form
expireDays = forms.IntegerField(required=False)
class Meta:
model = Invoice
(I used only one of the field declaration lines at a time. :)
I'm not even sure that I'm declaring the default value correctly. The only reference I could find to it was in an article on handling choices by James Bennett. I have yet to find it in the Django docs (I'm using version 1.2 - maybe it's in 1.3?)
Update - I tried setting the field's default value in the MySql database, to no effect. It seems as if, even when the form does not have a value for the field, it goes ahead and assigns null to the DB, over-riding the MySql default value.
Although I am currently just setting a default value in the view that creates the form - I don't really like that, since it puts the responsibility for the field's integrity in the view, not the DB.
The way I would have thought it would work, is that the field could be set, or not, in the form - if set, that value would be written to the DB, and if not set, the DB default would be used. Instead, if not set, the form is writing a null to the DB. So what's the point of having a default value in the ModelField declaration if it's not used? What exactly does it do?
i you want field to be optional - just leave second definition in the model and do not add anything in the form definition:
class Invoice(models.Model):
expireDays = models.PositiveSmallIntegerField(default=1, blank=True, null=True)
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoice
update, so in case there is no value set, use 1 as the field value:
class InvoiceForm(forms.ModelForm):
def clean_expireDays(self):
exp_days = self.cleaned_data.get('expireDays')
if exp_days is None:
return self.fields['expireDays'].initial
# above can be: return 1
# but now it takes value from model definition
else:
return exp_days
class Meta:
model = Invoice