How to create an alias for Django Model field?

15,272

Solution 1

I haven't looked into this very deeply, but intuitively, some of the following ways might get you started.

Custom manager

A custom manager with a modified get_queryset method to look for updatedOn when filtering for time.

Custom field type

It might be possible to create a custom field type which only acts as a reference to another field.

Hacking the model._meta.fields

The model object's _meta.fields seems to contain the list of fields in that object. Maybe you could try adding some kind of dummy field called time, which refers to the updatedOn field.

Solution 2

This old Django Snippet, worked for me, until Django 1.11. As @Jaberwocky commented virtual_only gets removed in Django 2.0

However, the deprecation warning reads that this field is deprecated in favor of private_only, although this is not mentioned in the features removed of the above link.

class AliasField(models.Field):
    # def contribute_to_class(self, cls, name, virtual_only=False):
    #       '''
    #           virtual_only is deprecated in favor of private_only
    #       '''
    #     super(AliasField, self).contribute_to_class(cls, name, virtual_only=True)
    #     setattr(cls, name, self)

    def contribute_to_class(self, cls, name, private_only=False):
        '''
            virtual_only is deprecated in favor of private_only
        '''
        super(AliasField, self).contribute_to_class(cls, name, private_only=True)
        setattr(cls, name, self)

    def __get__(self, instance, instance_type=None):
        return getattr(instance, self.db_column)


class Order(models.Model):
    """
    The main order model
    """
    number = AliasField(db_column='id')

Solution 3

Create a property for the field in your model:

class MyModel(moels.Model):
    updated_on = models.DateTimeField()

    def _get_time(self):
        return self.updated_on
    time = property(_get_time)

Solution 4

following miikkas's suggestion re model.Manager, I came up with the following that works for the much simpler case of retrieving the id field by querying uuid. the database was created with the ID being a varchar field used for a hexadecimal string, and I'm retrofitting a sequential integer ID field so I can use Django's auth module which requires it. and I want to do this in steps, hence the hack.

if DEVELOPMENT['merging_to_sequential_ids_incomplete']:
    class ModelManager(models.Manager):
        def get(self, *args, **kwargs):
            if 'uuid' in kwargs:
                kwargs['id'] = kwargs.pop('uuid')
            return super(ModelManager, self).get(*args, **kwargs)

class Model(models.Model):
    if DEVELOPMENT['merging_to_sequential_ids_incomplete']:
        print >>sys.stderr, 'WARNING: uuid now a synonym to id'
        id = models.CharField(max_length = 32,
            primary_key = True, default = uuid_string)
        objects = ModelManager()  # for Client.objects.get(uuid=...)
        uuid = property(lambda self: self.id)  # for client.uuid
    else:
        id = models.AutoField(primary_key = True)
        uuid = models.CharField(max_length = 32, ...

now I can:

cd myapp && ../djangopython manage.py shell
WARNING: uuid now a synonym to id
setting up special admin settings
Python 2.7.8 (default, Nov 18 2014, 16:29:10) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from myapp.models import *
>>> Client.objects.get(uuid=u'18b86bd7b58e4c0186f7654045ce81d9')
<Client: [email protected]>
>>> _.uuid
u'18b86bd7b58e4c0186f7654045ce81d9'

filter could be done the same way.

maybe this can help guide someone else looking for a way to use an "alias" or "synonym" for a Django model field. I don't believe it will help the OP though. the custom field type might be the better general approach.

Share:
15,272

Related videos on Youtube

NeoWang
Author by

NeoWang

Coder and Enterpreneur. Have worked on Web backend (Python/Django/Tornado), FrontEnd(jQuery/Backbone/Bootstrap/Angular), iOS/Android, embedded developement, also interested in Machine Learning/NLP stuff. Have cofounded a startup on a site-builder SaaS product, failed due to lack of marketing experience. Now working at an Internet start-up. SOreadytohelp

Updated on September 14, 2022

Comments

  • NeoWang
    NeoWang over 1 year

    My Django Model has a datetime field named 'updatedOn', I need to use a library function on this model to calculate some statistics, but the function assumes the datetime field name to be 'time', here is how the function uses the datetime:

    c = qset.filter(time__year=tt.year, time__month=tt.month, time__day=tt.day).count();
    

    Without touching the library code, how can I create an alias 'time' to refer to 'updatedOn' field, so that I can use the function?

  • NeoWang
    NeoWang over 10 years
    The property can be used to query the value, but cannot be used in qset.filter(time__year=tt.year...).
  • hellsgate
    hellsgate over 10 years
    Ah, that's annoying :-(
  • addohm
    addohm over 6 years
    brace yourself. Django 2.0 gets rid of virtual_only.
  • raratiru
    raratiru over 6 years
    @Jaberwocky Wow, thank you, that's the issue with the old snippets!
  • addohm
    addohm over 6 years
    no problem. For the record, in 2.0 you can mostly copy\paste the doc examples and they'll work (unlike 1.11). I did that and made some minor tweaks to add fields to the user model, as well as assign the id a UUID4. I used the source file templates and trimmed\styled them. It was pretty quick and painless.
  • raratiru
    raratiru over 6 years
    @Jaberwocky I found out the deprecation message which reads that virtual_only is removed in favor of private_only. This is not clear for some reason in the "removed features" section. I have updated the answer accordingly.
  • Vladimir Osintsev
    Vladimir Osintsev about 2 years
    This is also can be written inline as time = property(lambda self: self.updated_on)