Force a cascading delete for a Django model - django

I have a Django model with foreign-key relations that are marked as deletion.PROTECT, and I am OK with that behavior, since it's how the model should behave in most scenarios.
However, there is one use case for those models where I kind of need to do a "hard delete" (ie user wants to delete their account). In that case, I'd really like everything to behave like a CASCADE, instead of having to delete each of the foreign-key relationships manually. Is there a way to do this cleanly? In an ideal world, the model.delete() call would take a parameter that is something like force_cascade=True.

As django also creates the database with PROTECTED relations you need to do the cascading deletion yourself manually. The database itself will otherwise forbid the deletion.
Django's ORM can help you with that, the only thing you need to do is to find recursively all references to the user and delete them in reverse order.
It is also an advantage to do this manually as you might want to replace some occurrences of the user with a substitute (i.e. a virtual "deleted user"). I could think of comments in a message board that should be kept even so if the user deletes their account.
To find the relations pointing to the current user and replace them with a ghost user, you can use the following snippet.
from typing import List
from django.contrib.auth import get_user_model
from django.db.models import Model
from django.db.models.fields.reverse_related import (
ManyToOneRel,
ForeignObjectRel,
)
User = get_user_model()
def get_all_relations(model: Model) -> List[ForeignObjectRel]:
"""
Return all Many to One Relation to point to the given model
"""
result: List[ForeignObjectRel] = []
for field in model._meta.get_fields(include_hidden=True):
if isinstance(field, ManyToOneRel):
result.append(field)
return result
def print_updated(name, number):
"""
Simple Debug function
"""
if number > 0:
print(f" Update {number} {name}")
def delete_user_and_replace_with_substitute(user_to_delete: User):
"""
Replace all relations to user with fake replacement user
:param user_to_delete: the user to delete
"""
replacement_user: User = User.objects.get(pk=0) # define your replacement user
# replacement_user: User = User.objects.get(email='email#a.com')
for field in get_all_relations(user_to_delete):
field: ManyToOneRel
target_model: Model = field.related_model
target_field: str = field.remote_field.name
updated: int = target_model.objects.filter(
**{target_field: user_to_delete}
).update(**{target_field: replacement_user})
print_updated(target_model._meta.verbose_name, updated)
user_to_delete.delete()
For a real deletion simply replace the .update(...) function with a .delete() call (don't forget to recursively look for protected relations before, if needed)
There might be also a postgresql related solution that I am not aware of. The given solution is database independent.
In general it is a good idea to keep every relation PROTECTED to prevent accidentally deleting important database entries and delete manually with care.

models.PROTECT is a setting for the table in the database. You would have to issue raw SQL instructions to override it, and that would be database-specific (and I don't have a clue how to do that).
The alternative is to navigate the "tree" of objects that you want to remove, and then delete objects working from the protected "leaves" inwards to the "trunk". So if you had
class Bar( models.Model):
user = models.ForeignKey( User, models.PROTECT, ...)
...
class Foo( models.Model):
bar = models.ForeignKey( Bar, models.PROTECT, ... )
...
Then to delete a user object user you would need
def delete_user( user):
for bar in user.bar_set.all():
bar.foo_set.all().delete()
bar.delete()
user.delete()
I'd wrap it in a transaction so it either deleted everything or nothing.
It will hit the DB multiple times. I'm assuming that the number of related (bar, baz) objects is fairly small and that you won't be deleting users very often.
I have always wondered what one does if instance a has a protected foreign key relation to instance b and vice versa (maybe via intermediates). At face value this means you can create objects that are un-deleteable.

Related

Concise way of getting or creating an object with given field values

Suppose I have:
from django.db import models
class MyContentClass(models.Model):
content = models.TextField()
another_field = models.TextField()
x = MyContentClass(content="Hello, world!", another_field="More Info")
Is there a more concise way to perform the following logic?
existing = MyContentClass.objects.filter(content=x.content, another_field=x.another_field)
if existing:
x = existing[0]
else:
x.save()
# x now points to an object which is saved to the DB,
# either one we've just saved there or one that already existed
# with the same field values we're interested in.
Specifically:
Is there a way to query for both (all) fields without specifying
each one separately?
Is there a better idiom for either getting the old object or saving the new one? Something like get_or_create, but which accepts an object as a parameter?
Assume the code which does the saving is separate from the code which generates the initial MyContentClass instance which we need to compare to. This is typical of a case where you have a function which returns a model object without also saving it.
You could convert x to a dictionary with
x_data = x.__dict__
Then that could be passed into the object's get_or_create method.
MyContentClass.objects.get_or_create(**x_data)
The problem with this is that there are a few fields that will cause this to error out (eg the unique ID, or the _state Django modelstate field). However, if you pop() those out of the dictionary beforehand, then you'd probably be good to go :)
cleaned_dict = remove_unneeded_fields(x_data)
MyContentClass.objects.get_or_create(**cleaned_dict)
def remove_unneeded_fields(x_data):
unneeded_fields = [
'_state',
'id',
# Whatever other fields you don't want the new obj to have
# eg any field marked as 'unique'
]
for field in unneeded_fields:
del x_data[field]
return x_data
EDIT
To avoid issues associated with having to maintain a whitelist/blacklist of fields you, could do something like this:
def remove_unneeded_fields(x_data, MyObjModel):
cleaned_data = {}
for field in MyObjModel._meta.fields:
if not field.unique:
cleaned_data[field.name] = x_data[field.name]
return cleaned_Data
There would probably have to be more validation than simply checking that the field is not unique, but this might offer some flexibility when it comes to minor model field changes.
I would suggest to create a custom manager for those models and add the functions you want to do with the models (like a custom get_or_create function).
https://docs.djangoproject.com/en/1.10/topics/db/managers/#custom-managers
This would be the cleanest way and involves no hacking. :)
You can create specific managers for specific models or create a superclass with functions you want for all models.
If you just want to add a second manager with a different name, beware that it will become the default manager if you don't set the objects manager first (https://docs.djangoproject.com/en/1.10/topics/db/managers/#default-managers)

Copy Model Object From a Model To Another In Django

I have to model. I want to copy model object from a model to another:
Model2 is copy of Model1 (this models has too many m2m fields)
Model1:
class Profile(models.Model):
user = models.OneToOneField(User)
car = models.ManyToManyField(Car)
job = models.ManyToManyField(Job)
.
.
This is a survey application. I want to save user's profile when he/she attends the survey (because he can edit profile after survey)
I have created another model to save user profile when he takes survey (Im not sure its the right way)
class SurveyProfile(models.Model):
user = models.OneToOneField(SurveyUser) #this is another model that takes survey users
car = models.ManyToManyField(Car)
job = models.ManyToManyField(Job)
How can I copy user profile from Profile to SurveyProfile.
Thanks in advance
deepcopy etc won't work because the classes/Models are different.
If you're certain that SurveyProfile has the all of the fields present in Profile*, this should work (not tested it):
for field in instance_of_model_a._meta.fields:
if field.primary_key == True:
continue # don't want to clone the PK
setattr(instance_of_model_b, field.name, getattr(instance_of_model_a, field.name))
instance_of_model_b.save()
* (in which case, I suggest you make an abstract ProfileBase class and inherit that as a concrete class for Profile and SurveyProfile, but that doesn't affect what I've put above)
I'm having a tough time understanding what you wrote above, consequently I'm not 100% certain if this will work, but what I think I would do is something like this, if I'm understanding you right:
class Model2Form(ModelForm):
class Meta:
model = models.Model2
and then
f = Model2Form(**m1.__dict__)
if f.is_valid():
f.save()
But I think this looks more like poor database design then anything, without seeing the entire model1 I can't be certain. But, in any event, I'm not sure why you want to do that anyway, when you can simply use inheritance at the model level, or something else to get the same behavior.
Here's the function I've been using, it builds on model_to_dict. Model_to_dict just returns the ids of foreign keys + not their instances, so for those I replace them with the model itself.
def update_model(src, dest):
"""
Update one model with the content of another.
When it comes to Foreign Keys, they need to be
encoded using models and not the IDs as
returned from model_to_dict.
:param src: Source model instance.
:param dest: Destination model instance.
"""
src_dict = model_to_dict(src, exclude="id")
for k, v in src_dict.iteritems():
if isinstance(v, long):
m = getattr(src, k, None)
if isinstance(m, models.Model):
setattr(dest, k, m)
continue
setattr(dest, k, v)
This is how I do it (note: this is in Python3, you might need to change things - get rid of the dictionary comprehension - if you are using python 2):
def copy_instance_kwargs(src, exclude_pk=True, excludes=[]):
"""
Generate a copy of a model using model_to_dict, then make sure
that all the FK references are actually proper FK instances.
Basically, we return a set of kwargs that may be used to create
a new instance of the same model - or copy from one model
to another.
The resulting dictionary may be used to create a new instance, like so:
src_dict = copy_instance_kwargs(my_instance)
ModelClass(**src_dict).save()
:param src: Instance to copy
:param exclude_pk: Exclude the PK of the model, to ensure new records are copies.
:param excludes: A list of fields to exclude (must be a mutable iterable) from the copy. (date_modified, for example)
"""
# Exclude the PK of the model, since we probably want to make a copy.
if exclude_pk:
excludes.append(src._meta.pk.attname)
src_dict = model_to_dict(src, exclude=excludes)
fks={k: getattr(src, k) for k in src_dict.keys() if
isinstance(getattr(src, k, None), models.Model) }
src_dict.update(fks)
return src_dict
I came across something similar but I needed to check also if ForeignKey fields have compatible models. I end up with the following method:
def copy_object(obj, model):
kwargs = dict()
for field in model._meta.fields:
if hasattr(obj, field.name) and not field.primary_key:
if field.remote_field is not None:
obj_field = obj._meta.get_field(field.name)
if obj_field.remote_field != field.remote_field:
continue
kwargs[field.name] = getattr(obj, field.name)
return model(**kwargs)
So, if I'm interpreting your problem correctly, you have an old model (Profile), and you're trying to replace it with the new model SurveyProfile. Given the circumstances, you may want to consider using a database migration tool like South in the long run. For now, you can run a script in the Django shell (manage.py shell):
from yourappname.models import *
for profile in Profile.objects.all():
survey_profile = SurveyProfile()
# Assuming SurveyUser has user = ForeignKey(User)...
survey_profile.user = SurveyUser.objects.get(user=profile.user)
survey_profile.car = profile.car
survey_profile.job = profile.job
survey_profile.save()
Using South
If this project needs to be maintained and updated in the long term, I would highly recommend using a database migration package like South, which will let you modify fields on a Model, and migrate your database painlessly.
For example, you suggest that your original model had too many ManyToManyFields present. With South, you:
Delete the fields from the model.
Auto-generate a schema migration.
Apply the migration.
This allows you to reuse all of your old code without changing your model names or mucking with the database.

Django - Customizeable UserProfile

So I've got a UserProfile in Django that has certain fields that are required by the entire project - birthday, residence, etc. - and it also contains a lot of information that doesn't actually have any importance as far as logic goes - hometown, about me, etc. I'm trying to make my project a bit more flexible and applicable to more situations than my own, and I'd like to make it so that administrators of a project instance can add any fields they like to a UserProfile without having to directly modify the model. That is, I'd like an administrator of a new instance to be able to create new attributes of a user on the fly based on their specific needs. Due to the nature of the ORM, is this possible?
Well a simple solution is to create a new model called UserAttribute that has a key and a value, and link it to the UserProfile. Then you can use it as an inline in the django-admin. This would allow you to add as many new attributes to a UserProfile as you like, all through the admin:
models.py
class UserAttribute(models.Model):
key = models.CharField(max_length=100, help_text="i.e. Age, Name etc")
value = models.TextField(max_length=1000)
profile = models.ForeignKey(UserProfile)
admin.py
class UserAttributeInline(admin.StackedInline):
model = UserAttribute
class UserProfile(admin.ModelAdmin):
inlines = [UserAttibuteInline,]
This would allow an administrator to add a long list of attributes. The limitations are that you cant's do any validation on the input(outside of making sure that it's valid text), you are also limited to attributes that can be described in plain english (i.e. you won't be able to perform much login on them) and you won't really be able to compare attributes between UserProfiles (without a lot of Database hits anyway)
You can store additional data in serialized state. This can save you some DB hits and simplify your database structure a bit. May be the best option if you plan to use the data just for display purposes.
Example implementation (not tested)::
import yaml
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField('auth.User', related_name='profile')
_additional_info = models.TextField(default="", blank=True)
#property
def additional_info(self):
return yaml.load(self._additional_info)
#additional_info.setter
def additional_info(self, user_info_dict):
self._additional_info = yaml.dump(user_info_dict)
When you assign to profile.additional_info, say, a dictionary, it gets serialized and stored in _additional_info instead (don't forget to save the instance later). And then, when you access additional_info, you get that python dictionary.
I guess, you can also write a custom field to deal with this.
UPDATE (based on your comment):
So it appears that the actual problem here is how to automatically create and validate forms for user profiles. (It remains regardless on whether you go with serialized options or complex data structure.)
And since you can create dynamic forms without much trouble[1], then the main question is how to validate them.
Thinking about it... Administrator will have to specify validators (or field type) for each custom field anyway, right? So you'll need some kind of a configuration option—say,
CUSTOM_PROFILE_FIELDS = (
{
'name': 'user_ip',
'validators': ['django.core.validators.validate_ipv4_address'],
},
)
And then, when you're initializing the form, you define fields with their validators according to this setting.
[1] See also this post by Jacob Kaplan-Moss on dynamic form generation. It doesn't deal with validation, though.

Django - Cascade deletion in ManyToManyRelation

Using the following related models (one blog entry can have multiple revisions):
class BlogEntryRevision(models.Model):
revisionNumber = models.IntegerField()
title = models.CharField(max_length = 120)
text = models.TextField()
[...]
class BlogEntry(models.Model):
revisions = models.ManyToManyField(BlogEntryRevision)
[...]
How can I tell Django to delete all related BlogEntryRevisions when the corresponding BlogEntry is deleted? The default seems to be to keep objects in a many-to-many relation if an object of the "other" side is deleted. Any way to do this - preferably without overriding BlogEntry.delete?
I think you are misunderstanding the nature of a ManyToMany relationship. You talk about "the corresponding BlogEntry" being deleted. But the whole point of a ManyToMany is that each BlogEntryRevision has multiple BlogEntries related to it. (And, of course, each BlogEntry has multiple BlogEntryRevisions, but you know that already.)
From the names you have used, and the fact that you want this deletion cascade functionality, I think you would be better off with a standard ForeignKey from BlogEntryRevision to BlogEntry. As long as you don't set null=True on that ForeignKey, deletions will cascade - when the BlogEntry is deleted, all Revisions will be too.
As Of Django 2.0
The ForeignKey initializer now requires you to specify the on_delete parameter:
from django.db import models
from .models import MyRelatedModel
class model(models.Model):
related_model = models.ForeignKey(MyRelatedModel, on_delete=models.CASCADE)
I had this exact use-case today:
Model Author: can have several entries
Model Entry: can have several authors
For this, I'm using a ManyToManyRelationship.
My use-case was: if I delete the last entry of a particular author, then this author should be deleted as well.
The solution can be achieved using the pre_delete signal:
#receiver(pre_delete, sender=Entry)
def pre_delete_story(sender, instance, **kwargs):
for author in instance.authors.all():
if author.entries.count() == 1 and instance in author.entries.all():
# instance is the only Entry authored by this Author, so delete it
author.delete()
Simply use the clear() method to remove related objects since Django uses a through model to specify the relationships the clear method removes all related BlogEntryRevision
be = BlogEntry.objects.get(id=1)
be.blogentryrevision_set.clear()
You can use a custom model manager, but the documentation seems to indicate that it does do something like this already and I can't recall exactly what this means:
The delete method, conveniently, is
named delete(). This method
immediately deletes the object and has
no return value. Example:
e.delete()
You can also delete objects
in bulk. Every QuerySet has a delete()
method, which deletes all members of
that QuerySet.
For example, this deletes all Entry
objects with a pub_date year of 2005:
Entry.objects.filter(pub_date__year=2005).delete()
Keep in mind that this will, whenever
possible, be executed purely in SQL,
and so the delete() methods of
individual object instances will not
necessarily be called during the
process. If you've provided a custom
delete() method on a model class and
want to ensure that it is called, you
will need to "manually" delete
instances of that model (e.g., by
iterating over a QuerySet and calling
delete() on each object individually)
rather than using the bulk delete()
method of a QuerySet.
When Django deletes an object, it
emulates the behavior of the SQL
constraint ON DELETE CASCADE -- in
other words, any objects which had
foreign keys pointing at the object to
be deleted will be deleted along with
it. For example:
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

Creation of dynamic model fields in django

This is a problem concerning django.
I have a model say "Automobiles". This will have some basic fields like "Color","Vehicle Owner Name", "Vehicle Cost".
I want to provide a form where the user can add extra fields depending on the automobile that he is adding. For example, if the user is adding a "Car", he will extra fields in the form, dynamically at run time, like "Car Milage", "Cal Manufacturer".
Suppose if the user wants to add a "Truck", he will add "Load that can be carried", "Permit" etc.
How do I achieve this in django?
There are two questions here:
How to provide a form where the user can add new fields at run time?
How to add the fields to the database so that it can be retrieved/queried later?
There are a few approaches:
key/value model (easy, well supported)
JSON data in a TextField (easy, flexible, can't search/index easily)
Dynamic model definition (not so easy, many hidden problems)
It sounds like you want the last one, but I'm not sure it's the best for you. Django is very easy to change/update, if system admins want extra fields, just add them for them and use south to migrate. I don't like generic key/value database schemas, the whole point of a powerful framework like Django is that you can easily write and rewrite custom schemas without resorting to generic approaches.
If you must allow site users/administrators to directly define their data, I'm sure others will show you how to do the first two approaches above. The third approach is what you were asking for, and a bit more crazy, I'll show you how to do. I don't recommend using it in almost all cases, but sometimes it's appropriate.
Dynamic models
Once you know what to do, this is relatively straightforward. You'll need:
1 or 2 models to store the names and types of the fields
(optional) An abstract model to define common functionality for your (subclassed) dynamic models
A function to build (or rebuild) the dynamic model when needed
Code to build or update the database tables when fields are added/removed/renamed
1. Storing the model definition
This is up to you. I imagine you'll have a model CustomCarModel and CustomField to let the user/admin define and store the names and types of the fields you want. You don't have to mirror Django fields directly, you can make your own types that the user may understand better.
Use a forms.ModelForm with inline formsets to let the user build their custom class.
2. Abstract model
Again, this is straightforward, just create a base model with the common fields/methods for all your dynamic models. Make this model abstract.
3. Build a dynamic model
Define a function that takes the required information (maybe an instance of your class from #1) and produces a model class. This is a basic example:
from django.db.models.loading import cache
from django.db import models
def get_custom_car_model(car_model_definition):
""" Create a custom (dynamic) model class based on the given definition.
"""
# What's the name of your app?
_app_label = 'myapp'
# you need to come up with a unique table name
_db_table = 'dynamic_car_%d' % car_model_definition.pk
# you need to come up with a unique model name (used in model caching)
_model_name = "DynamicCar%d" % car_model_definition.pk
# Remove any exist model definition from Django's cache
try:
del cache.app_models[_app_label][_model_name.lower()]
except KeyError:
pass
# We'll build the class attributes here
attrs = {}
# Store a link to the definition for convenience
attrs['car_model_definition'] = car_model_definition
# Create the relevant meta information
class Meta:
app_label = _app_label
db_table = _db_table
managed = False
verbose_name = 'Dynamic Car %s' % car_model_definition
verbose_name_plural = 'Dynamic Cars for %s' % car_model_definition
ordering = ('my_field',)
attrs['__module__'] = 'path.to.your.apps.module'
attrs['Meta'] = Meta
# All of that was just getting the class ready, here is the magic
# Build your model by adding django database Field subclasses to the attrs dict
# What this looks like depends on how you store the users's definitions
# For now, I'll just make them all CharFields
for field in car_model_definition.fields.all():
attrs[field.name] = models.CharField(max_length=50, db_index=True)
# Create the new model class
model_class = type(_model_name, (CustomCarModelBase,), attrs)
return model_class
4. Code to update the database tables
The code above will generate a dynamic model for you, but won't create the database tables. I recommend using South for table manipulation. Here are a couple of functions, which you can connect to pre/post-save signals:
import logging
from south.db import db
from django.db import connection
def create_db_table(model_class):
""" Takes a Django model class and create a database table, if necessary.
"""
table_name = model_class._meta.db_table
if (connection.introspection.table_name_converter(table_name)
not in connection.introspection.table_names()):
fields = [(f.name, f) for f in model_class._meta.fields]
db.create_table(table_name, fields)
logging.debug("Creating table '%s'" % table_name)
def add_necessary_db_columns(model_class):
""" Creates new table or relevant columns as necessary based on the model_class.
No columns or data are renamed or removed.
XXX: May need tweaking if db_column != field.name
"""
# Create table if missing
create_db_table(model_class)
# Add field columns if missing
table_name = model_class._meta.db_table
fields = [(f.column, f) for f in model_class._meta.fields]
db_column_names = [row[0] for row in connection.introspection.get_table_description(connection.cursor(), table_name)]
for column_name, field in fields:
if column_name not in db_column_names:
logging.debug("Adding field '%s' to table '%s'" % (column_name, table_name))
db.add_column(table_name, column_name, field)
And there you have it! You can call get_custom_car_model() to deliver a django model, which you can use to do normal django queries:
CarModel = get_custom_car_model(my_definition)
CarModel.objects.all()
Problems
Your models are hidden from Django until the code creating them is run. You can however run get_custom_car_model for every instance of your definitions in the class_prepared signal for your definition model.
ForeignKeys/ManyToManyFields may not work (I haven't tried)
You will want to use Django's model cache so you don't have to run queries and create the model every time you want to use this. I've left this out above for simplicity
You can get your dynamic models into the admin, but you'll need to dynamically create the admin class as well, and register/reregister/unregister appropriately using signals.
Overview
If you're fine with the added complication and problems, enjoy! One it's running, it works exactly as expected thanks to Django and Python's flexibility. You can feed your model into Django's ModelForm to let the user edit their instances, and perform queries using the database's fields directly. If there is anything you don't understand in the above, you're probably best off not taking this approach (I've intentionally not explained what some of the concepts are for beginners). Keep it Simple!
I really don't think many people need this, but I have used it myself, where we had lots of data in the tables and really, really needed to let the users customise the columns, which changed rarely.
Database
Consider your database design once more.
You should think in terms of how those objects that you want to represent relate to each other in the real world and then try to generalize those relations as much as you can, (so instead of saying each truck has a permit, you say each vehicle has an attribute which can be either a permit, load amount or whatever).
So lets try it:
If you say you have a vehicle and each vehicle can have many user specified attributes consider the following models:
class Attribute(models.Model):
type = models.CharField()
value = models.CharField()
class Vehicle(models.Model):
attribute = models.ManyToMany(Attribute)
As noted before, this is a general idea which enables you to add as much attributes to each vehicle as you want.
If you want specific set of attributes to be available to the user you can use choices in the Attribute.type field.
ATTRIBUTE_CHOICES = (
(1, 'Permit'),
(2, 'Manufacturer'),
)
class Attribute(models.Model):
type = models.CharField(max_length=1, choices=ATTRIBUTE_CHOICES)
value = models.CharField()
Now, perhaps you would want each vehicle sort to have it's own set of available attributes. This can be done by adding yet another model and set foreign key relations from both Vehicle and Attribute models to it.
class VehicleType(models.Model):
name = models.CharField()
class Attribute(models.Model):
vehicle_type = models.ForeigngKey(VehicleType)
type = models.CharField()
value = models.CharField()
class Vehicle(models.Model):
vehicle_type = models.ForeigngKey(VehicleType)
attribute = models.ManyToMany(Attribute)
This way you have a clear picture of how each attribute relates to some vehicle.
Forms
Basically, with this database design, you would require two forms for adding objects into the database. Specifically a model form for a vehicle and a model formset for attributes. You could use jQuery to dynamically add more items on the Attribute formset.
Note
You could also separate Attribute class to AttributeType and AttributeValue so you don't have redundant attribute types stored in your database or if you want to limit the attribute choices for the user but keep the ability to add more types with Django admin site.
To be totally cool, you could use autocomplete on your form to suggest existing attribute types to the user.
Hint: learn more about database normalization.
Other solutions
As suggested in the previous answer by Stuart Marsh
On the other hand you could hard code your models for each vehicle type so that each vehicle type is represented by the subclass of the base vehicle and each subclass can have its own specific attributes but that solutions is not very flexible (if you require flexibility).
You could also keep JSON representation of additional object attributes in one database field but I am not sure this would be helpfull when querying attributes.
Here is my simple test in django shell- I just typed in and it seems work fine-
In [25]: attributes = {
"__module__": "lekhoni.models",
"name": models.CharField(max_length=100),
"address": models.CharField(max_length=100),
}
In [26]: Person = type('Person', (models.Model,), attributes)
In [27]: Person
Out[27]: class 'lekhoni.models.Person'
In [28]: p1= Person()
In [29]: p1.name= 'manir'
In [30]: p1.save()
In [31]: Person.objects.a
Person.objects.aggregate Person.objects.all Person.objects.annotate
In [32]: Person.objects.all()
Out[33]: [Person: Person object]
It seems very simple- not sure why it should not be a considered an option- Reflection is very common is other languages like C# or Java- Anyway I am very new to django things-
Are you talking about in a front end interface, or in the Django admin?
You can't create real fields on the fly like that without a lot of work under the hood. Each model and field in Django has an associated table and column in the database. To add new fields usually requires either raw sql, or migrations using South.
From a front end interface, you could create pseudo fields, and store them in a json format in a single model field.
For example, create an other_data text field in the model. Then allow users to create fields, and store them like {'userfield':'userdata','mileage':54}
But I think if you're using a finite class like vehicles, you would create a base model with the basic vehicle characteristics, and then create models that inherits from the base model for each of the vehicle types.
class base_vehicle(models.Model):
color = models.CharField()
owner_name = models.CharField()
cost = models.DecimalField()
class car(base_vehicle):
mileage = models.IntegerField(default=0)
etc