Determine if Django model has a default - django

I want to know if there is a way programmatically of finding the default assigned to a field on any model, I have the model instance and the field names.
In the below model I would have to get the default from u_value, allow_profile and disabled if they are Null to be able to save the data correctly. The Database is Firebird
Eg model:
class Fitting(models.Model):
uuid = UUIDField(primary_key=True)
bought_in_control_panel_file = models.ForeignKey(BoughtInControlPanelFile, db_column='bought_in_control_panel_file_id',null=True, blank=True)
name = models.CharField(_('name'),null=True, blank=False,max_length=255)
code = models.CharField(_('Code'),null=True, blank=True,max_length=255)
fire_rating = models.ForeignKey(FireRating, db_column='fire_rating_id',null=True, blank=True)
u_value = models.FloatField(_('U-value'),default=0)
acoustic_rating = models.FloatField(_('Acoustic Rating'),default=0)
allow_profile = models.BooleanField(default=0)
disabled = models.BooleanField(default=0)
date_time_updated = models.DateTimeField(null=True, blank=True, auto_now=True)

model_field.get_default() returns the default assigned to a model field
Example:
model = Polls.objects.all()
for model_field in model:
print model_field.get_default()

Django will automatically save the model instance with default values when you save it and haven't set the required non-null fields.
Doesn't your object saved in DB with default values when they are not set explicitly?
The value for default property can be a function which will be called when new object will be saved. You may want to try that too.

Related

ForeignKey updates aren't cascading on Django created tables in Postgres

This is the error that I get when I try to update the value in the "parent" table that the foreign key is looking at in a related table:
ERROR: update or delete on table "product" violates foreign key constraint "pd_family_product_guid_ada83db3_fk_product_guid" on table "pd_family"
DETAIL: Key (guid)=(902d30b8-26ba-ea11-a812-000d3a5bbb60) is still referenced from table "pd_family".
SQL state: 23503
This is what I have for my models:
class Product(models.Model):
guid = models.UUIDField(primary_key=True)
product = models.CharField(max_length=10)
year = models.IntegerField()
previous_product_name = models.CharField(max_length=10)
class StandardProductFieldsMixin(models.Model):
product_guid = models.ForeignKey('Product', on_delete=models.CASCADE, db_column='product_guid')
class Meta:
abstract = True
class ActiveFieldMixin(models.Model):
active = models.BooleanField()
class Meta:
abstract = True
class Family(StandardProductFieldsMixin, ActiveFieldMixin):
new_code = models.IntegerField(null=True)
code = models.DecimalField(max_digits=20, decimal_places=2)
title = models.CharField(max_length=255)
desc = models.TextField(null=True)
fam_desc = models.TextField(null=True)
When I try to change a value of guid in Product, my expectation is that it would automatically change it in Family as well. I'm trying to change it with something like:
UPDATE product
SET guid = '902D30B8-26BA-EA11-A812-000D3A5BBB6B'
WHERE guid = '902D30B8-26BA-EA11-A812-000D3A5BBB60'
I guess I was under the wrong impression. Do I need to do something additional in the model? Looked at the documentation for something like on_update, but not seeing that either an **options or as a parameter for models.ForeignKey.
From what I gather after reading about it for more than an hour, if I want this kind of functionality I just need to add it Postgres manual, by dropping the constraint and adding it back with ON UPDATE CASCADE.
Apparently I'm under the wrong impression:
https://stackoverflow.com/a/61648910/3123109
Sounds like Django model migrations implement neither ON DELETE nor ON UPDATE database CASCADES options. I guess I'd need to drop into the database and implement them there.

Update multiple fields of member of an instance simultaneously

Suppose I have a User model and this model
class modelEmployer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
employer_image = models.ImageField(upload_to='images/', default='')
Now suppose i have an instance of modelEmployer and I would like to update the content of the user object in it. I know I can do this
instance.user.email = new value
instance.first_name = new value
instance.save()
I read we can run an update on a queryset (even if it returns one object). Now suppose I have a dictionary like this
dict = {"first_name : "John","last_name" : "deer",....}
How can i do something like this
modelEmployer.object.filter(instance.user.email=dict["email"]).update(only update the user objects as I would like to update the user object of this field using directly the dictionary. Any suggestions ?
You can use explicitly mention the relation and do it,
dict = {"user__first_name" : "John","user__last_name" : "deer",....}
And in the ORM, do as
modelEmployer.object.filter(instance.user.email=dict["email"]).update(**dict)
Hope this will solve your issue

Tablename with ID "Some_ID" doesn't exist. Perhaps it was deleted? Django Sqlite

I have database with many tables; three of those which are interlinked via primary and foreign keys are "Vendor_Details" , "Channel_Details" and "MSO_Details"
models.py
class Vendor_Details(models.Model):
class Meta:
verbose_name_plural = "Vendor_Details"
vendor_name = models.CharField(primary_key = True,max_length=50)
mso_id = models.CharField(unique = True, max_length=20)
class Channel_Details(models.Model):
class Meta:
verbose_name_plural = "Channel_Details"
channel_id = models.CharField(primary_key = True, max_length=20)
vendor_name = models.ForeignKey(Vendor_Details, on_delete=models.CASCADE)
channel_logo = models.CharField(max_length=50)
channel_name = models.CharField(max_length=50)
class MSO_Details(models.Model):
class Meta:
verbose_name_plural = "MSO_Details"
mso_id = models.ForeignKey(Vendor_Details, on_delete=models.CASCADE)
channel_id = models.ForeignKey(Channel_Details, on_delete=models.CASCADE)
channel_number = models.PositiveIntegerField()
So,
Channel_Details is linked to Vendor_Details with vendor_name and
MSO_Details is linked with Vendor_Details and Channel_Details with mso_id and channel_id respectively.
Now, I am inside Django's Administrator's MSO_Details table and trying to click on edit icon of CHANNEL ID column i get a new window opens with message Channel_ details with ID "CH6" doesn't exist. Perhaps it was deleted? May be this is because channel_id is primary key of reference table and DB will not allow the changes? But then the message should had been something different. How can i handle this situation? I clicked on edit for CH_006 and message shows CH6. I am confused whats going on here, what is django's DB refering to here?
Note : I can very well add new CHANNEL_DETAILS after click add button.
I had this kind problem for the last two days and the problem was
1. If on adding details to a new form initially, you do not add the right field required.(I was including both text and integers to a field that was only CharField)
2.The other solution when the error came again was to delete migrations and the database itself and create a new database again(Using the same database name).
In my case, I had an existing SQLite database that I've been migration over to Django. All my entities had a UUID column as their primary key.
I had set the primary key column as django.models.UUIDField thinking that Django would support it, but it doesn't.
So I converted it to a text field with UUID as default value, it started working again.
class Model(models.Model):
# id = models.UUIDField(primary_key=True)
id = models.TextField(primary_key=True, default=uuid.uuid4)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True

Django forms: default value if user leaves field blank

On Django Forms, how do I specify a default value for a field if the user leaves it blank? Initial sets an initial value, but the user can delete this.
If you're using a ModelForm simply follow Dan's advice.
If however you're simply using a Form then you may have to specify how to deal with validation. Example Documentation
class YourForm(forms.Form):
...
def clean_field(self):
data = self.cleaned_data['field']
if not data:
data = 'default value'
return data
Set a default value in the model.
class YourModel(models.Model):
this_field = models.TextField(default="default_value")
WallyBay's answer works for me.
(+adding my experience)
If you leave the form field empty, None value will be passed.
you can check this by printing out from.cleaned_data().
But, in my case, None value wasn't replaced with the Model's default value.
I tested by creating objects in the shell('python manage.py shell')
passing 1)None value and 2)empty parameter.
My Model:
class Cart(models.Model):
total_amount = models.DecimalField(decimal_places=2, max_digits=1000, default=1, blank=True, null=True)
quantity = models.IntegerField(default=1, blank=True)
note = models.CharField(max_length=300, default='nothing to mention')
summery = models.TextField(blank=False, null=True)
event_won = models.BooleanField(default=False)
My Form:
class CartForm(forms.ModelForm):
summery = forms.CharField()
total_amount = forms.DecimalField(required=False)
quantity = forms.IntegerField(initial=20)
note = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"write a note"}))
class Meta:
model = Cart
fields = [
'summery',
'total_amount',
'quantity',
'note'
]
1) create the object by passing None value.
Cart.objects.create(total_amount=None)
Result: Default value didn't apply. The total_amount is Null(None).
2) create the object without passing any.
Cart.objects.create()
Result: default value worked. total_amount is 1.
When I delete null=True option for the total_amount in the Model class, it gives me an error 'NOT NULL constraint failed'

Access foreign key fields from Admin Tabular Inline

I'm trying to access a field of a foreign key within a Tabular Inline in the Django Admin.
Despite my best efforts I can't seem to get it working. My current code is:
class RankingInline(admin.TabularInline):
model = BestBuy.products.through
fields = ('product', 'account_type', 'rank')
readonly_fields = ('product', 'rank')
ordering = ('rank',)
extra = 0
def account_type(self, obj):
return obj.products.account_type
Which results in:
'RankingInline.fields' refers to field 'account_type' that is missing from the form.
I have also tried using the model__field method, which I used as:
fields = ('product', 'product__account_type', 'rank')
Which results in:
'RankingInline.fields' refers to field 'product__account_type' that is missing from the form.
The models are defined as so:
class Product(BaseModel):
account_type = models.CharField(choices=ACCOUNT_TYPE_OPTIONS, verbose_name='Account Type', max_length=1, default='P')
class Ranking(models.Model):
product = models.ForeignKey(Product)
bestbuy = models.ForeignKey(BestBuy)
rank = models.IntegerField(null=True, blank = True)
class BestBuy(BaseModel):
products = models.ManyToManyField(Product, through='Ranking')
class BaseModel(models.Model):
title = models.CharField(max_length = TODO_LENGTH)
slug = models.CharField(max_length = TODO_LENGTH, help_text = """The slug is a url encoded version of your title and is used to create the web address""")
created_date = models.DateTimeField(auto_now_add = True)
last_updated = models.DateTimeField(auto_now = True)
What am I doing wrong?
I think what you are looking for is nested inlines since you want to expand "Product" as inline within RankingInline. At present Django does not have such feature built in. This question is relevant: Nested inlines in the Django admin?
You can also look at "Working with many-to-many intermediary models" section in Django DOC. That might be useful.
Actually Django will show you a small green '+' button besides the inline product field entry which you can use to create a new product to assign to your current entry for BestBuy. This might be an alternative for you to use.
You simply need to add the method-field to readonly_fields:
readonly_fields = ('product', 'rank', 'account_type')
Your new field account_type should be defined in ModelAdmin (i.e. RankingAdmin) not in TabularInline (i. e. RankingInline). It should be only accessed from TabularInline.