Overriding Fields in a Django Model

I want to add several fields to each model in my django application. This time it's created_at , updated_at and notes . Duplicate code for every 20 models seems dumb. So, I decided to use an abstract base class that will add these fields. The problem is that the fields inherited from the abstract base class are included in the list of fields in admin. Declaring the field order for each ModelAdmin class is not an option, it even duplicates the code than with the manual field instruction.

In my final solution, I modified the model constructor to override fields in _meta before creating a new instance:

 class MyModel(models.Model): # Service fields notes = my_fields.NotesField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: abstract = True last_fields = ("notes", "created_at", "updated_at") def __init__(self, *args, **kwargs): new_order = [f.name for f in self._meta.fields] for field in self.last_fields: new_order.remove(field) new_order.append(field) self._meta._field_name_cache.sort(key=lambda x: new_order.index(x.name)) super(MyModel, self).__init__(*args, **kwargs) class ModelA(MyModel): field1 = models.CharField() field2 = models.CharField() #etc ... 

It works as intended, but I wonder if there is a better way to achieve my goal?

+7
python django django-models
source share
3 answers

If you basically need an order for a Django administrator, you can also create your own β€œgeneral” -admin class through a subclass of the Django admin class. See http://docs.djangoproject.com/en/dev/intro/tutorial02/#customize-the-admin-form for setting the display of fields in the administrator. You can overwrite admin __init__ to set up the fields / fields to create an admin instance as you wish. For example. you can do something like:

 class MyAdmin(admin.ModelAdmin): def __init__(self, model, admin_site): general_fields = ['notes', 'created_at', 'updated_at'] fields = [f.name for f in self.model._meta.fields if f.name not in general_fields] self.fields = fields + general_fields super(admin.ModelAdmin, self).__init__(model, admin_site) 

In addition, I believe that it is not a good practice to modify (private) _field_name_cache !

+5
source share

I had the same problem, but I found these solutions problematic, so here is what I did:

 class BaseAdmin(admin.ModelAdmin): def get_fieldsets(self, request, obj = None): res = super(BaseAdmin, self).get_fieldsets(request, obj) # I only need to move one field; change the following # line to account for more. res[0][1]['fields'].append(res[0][1]['fields'].pop(0)) return res 

Changing the set of fields in the admin makes more sense to me than changing the fields in the model.

+7
source share

I also did not like other solutions, so I just changed the migration files directly.

Whenever you create a new table in models.py, you will need to run "python manage.py makemigrations" (I find this in Django> = v1.7.5). Once you do this, open the newly created migration file in the directory your_app_path / migrations / and simply move the lines in the order you want it to be. Then run "python manage.py migrate". Voila! By going to "python manage.py dbshell", you can see that the order of the columns is exactly the way you wanted them!

Downside to this method: you have to do it manually for each table you create, but, fortunately, the overhead is minimal. And this can be done only when creating a new table, and not in modifying an existing one.

0
source share

All Articles