Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Model Field Default Based Off Another Field in Same Model

I have a model that I would like to contain a subjects name and their initials (he data is somewhat anonymized and tracked by initials).

Right now, I wrote

class Subject(models.Model):      name = models.CharField("Name", max_length=30)     def subject_initials(self):         return ''.join(map(lambda x: '' if len(x)==0 else x[0],                            self.name.split(' ')))     # Next line is what I want to do (or something equivalent), but doesn't work with     # NameError: name 'self' is not defined     subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials) 

As indicated by the last line, I would prefer to be able to have the initials actually get stored in the database as a field (independent of name), but that is initialized with a default value based on the name field. However, I am having issues as django models don't seem to have a 'self'.

If I change the line to subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials), I can do the syncdb, but can't create new subjects.

Is this possible in Django, having a callable function give a default to some field based on the value of another field?

(For the curious, the reason I want to separate my store initials separately is in rare cases where weird last names may have different than the ones I am tracking. E.g., someone else decided that Subject 1 Named "John O'Mallory" initials are "JM" rather than "JO" and wants to fix edit it as an administrator.)

like image 716
dr jimbob Avatar asked Dec 07 '10 19:12

dr jimbob


People also ask

Can Django model have two primary keys?

Do Django models support multiple-column primary keys? ¶ No. Only single-column primary keys are supported.

What is Onetoone field in Django?

One-to-one fields:This is used when one record of a model A is related to exactly one record of another model B. This field can be useful as a primary key of an object if that object extends another object in some way. For example – a model Car has one-to-one relationship with a model Vehicle, i.e. a car is a vehicle.

What is auto field in Django?

According to documentation, An AutoField is an IntegerField that automatically increments according to available IDs. One usually won't need to use this directly because a primary key field will automatically be added to your model if you don't specify otherwise.

How do you add a new field to a model with new Django migrations?

To answer your question, with the new migration introduced in Django 1.7, in order to add a new field to a model you can simply add that field to your model and initialize migrations with ./manage.py makemigrations and then run ./manage.py migrate and the new field will be added to your DB.


2 Answers

Models certainly do have a "self"! It's just that you're trying to define an attribute of a model class as being dependent upon a model instance; that's not possible, as the instance does not (and cannot) exist before your define the class and its attributes.

To get the effect you want, override the save() method of the model class. Make any changes you want to the instance necessary, then call the superclass's method to do the actual saving. Here's a quick example.

def save(self, *args, **kwargs):     if not self.subject_init:         self.subject_init = self.subject_initials()     super(Subject, self).save(*args, **kwargs) 

This is covered in Overriding Model Methods in the documentation.

like image 157
Elf Sternberg Avatar answered Sep 24 '22 02:09

Elf Sternberg


I don't know if there is a better way of doing this, but you can use a signal handler for the pre_save signal:

from django.db.models.signals import pre_save  def default_subject(sender, instance, using):     if not instance.subject_init:         instance.subject_init = instance.subject_initials()  pre_save.connect(default_subject, sender=Subject) 
like image 39
Gabi Purcaru Avatar answered Sep 22 '22 02:09

Gabi Purcaru