I am planning to use a same user model for two different users with some additional fields in one model. Is it possible to do this in Django? If it is possible, how can I do it?
You have two options :
Firstly
You create a new Model (call it ExtendedUser) and you put the extra fields in that model.
You then set your ExtendedUser model to inherit from your MainUser model. This will create two tables with a one to one link between them.
The advantage of this is that your ExtendedUser model will inherit any methods defined in your original MainUser model, and you only need add methods to the ExtendedUser model if you absolutely have to. You can also write functions which can deal with both the MainUser and ExtendedUser models easily, since they are all instances of the MainUser model. One of the benefits of using inhertiance is if you write a query on the ExtendedUser model fetching all fields, it well fetch the MainUser fields too.
A Second (worse) option :
Have a single extended model with a flag on it which says whether to use the extra fields. This can be made to work, but will make your queries more complex, and if you need the extra fields to be indexed, the indexes are likely to be a bit less efficient.
Note : having a second table with a relationship between the two is no bad thing in SQL - that is how data is normally managed. Having special optional fields for some types of users isn't great as mentioned.
Related
I have an abstract base model ('Base') from which two models inherit: 'Movie' and 'Cartoon'. I display a list of both movies and cartoons to the user (with the help of itertools.chain). Then I want to give the user the opportunity to delete any of these items, without knowing in advance whether it is a movie or a cartoon. I am trying to do it like this:
...
movies = Movie.objects.filter(user_created=userlist).order_by('title')
cartoons = Cartoon.objects.filter(user_created=userlist).order_by('title')
all_items = list(chain(movies, cartoons))
item = all_items.get(id=item_id)
item.delete()
But then PyCharm states,
Unresolved attribute reference 'get' for class 'list'
I understand why this happens but I don't know how to avoid it. Is there any way to merge two querysets from different models and apply get or filter without removing the abstract base model and creating a physical parent model?
You could use the ContentTypes framework for a generic and reusable solution to this for an arbitrary number of different models. But I also wonder why Cartoon and Movie must be different types to begin with; it may be worth spending a little time thinking about whether you can use a single model for both types of media - deletion of an arbitrary instance is just one of many cases where a single model will be more straightforward than relying on something like ContentTypes.
EDIT: For more info on ContentTypes. You could either create a base model with a generic relation (you said you didn't want to do this), or for the deletion you could include app label and model name in the request data alongside item id, enabling lookups like:
media_type = ContentType.objects.get(app_label=app_label, model=model_name)
instance = media_type.get_object_for_this_type(id=item_id)
instance.delete()
what's nice about this approach is you'd barely have to change your model structure.
you can first find the index using index() method and then can get item by all_items[given_index].delete()
In my project i have many models in multiple apps, all of them inherit from one abstract model. I would like to create a model that would hold the changes to the history for every one of my models, so that every model would have its own history model. Each model would also have one-to-many relation to its history model. All history models would be the same, except for the foreign key to their respective model.
My problem is that I do not want to write all the history models manually. Instead i would like to have the history model created for every model automatically, so I don't have to write all that boilerplate code. Can this be achieved?
There is a widely-used django package that I believe solves this exact problem called django-reversion with a nice API. I recommend using it if it fits your needs rather than building a custom solution.
Object version control is usually better solved by serializing your objects and storing the serialization every time they are edited (e.g. in the json format).
You may also want to keep track of when objects are deleted.
This way, you only need to store a reference to the serialized object. Versions of all objects can live in the same database table and reference their "source" object using Django's generic relations.
You can eventually create your classes dynamically with type()
There is many ways to do it, but you can do something as follows:
class SomeParentClass: pass
NewClass = type('NewClass', (SomeParentClass,), {'new_method': lambda self:
'foo' } )
new_class_instance = NewClass()
print(new_class_instance.new_method())
So you can create models dynamically, with a different name, inherit from a different class, new methods...
You can then use globals()[variable_name_to_store_class] to assign newly created classes to a dynamic variable name.
Hope its relavant for your problem.
Can I add additional fields to ModelSerializer subclass?
By saying 'additional field', I mean some fields don't belong any models in database, which any effort that try to map those fields to exist model fields will fail. The reason I need to include those fields is for design purpose. I need to those fields' value to do the validation and creating a new instance eventually.
I know there is a kwarg in ModelSerialzer called 'context'. By putting all the additional information into 'context', it will work. However, I want to know is that possible to create additional fields?
I have tried adding 'write_only=True', which doesn't work. The only left option is to override default restore_object method to create the instance with my will.
Any other ideas?
As you have not posted any code I can only give you a generic answer, but if I understand you correctly, you wish to add a custom field to a ModelSerializer thats not part of your model...
In DSF you can do this very esaily (read here):
In this case you just want a simple read-only field, so instead just use:
custom_field = Field(source='get_whatever')
In terms if validation after that please read the DRF guide here
I have 2 models: a and b
I want to build a many to many relashionship and I will use the link model method, thus I need to create an a_to_b_membership model.
The question is:
Should I put the model class on the a model file?
The b model file?
Or create a new model file?
If I need to create a new model file, then how should I name it?
It makes absolutely no difference.
Firstly, however, you should realize that there's no need to have a separate file for each model. It's perfectly normal to have several model classes in one models.py file. The division is between separate apps, each of which group together related models.
Secondly, you should also realize that unless you have a specific need to add extra data on the many-to-many relationship, you don't need to create a link table. Django will take care of that for you once you define a ManyToManyField.
Does anyone can tell me if it's possible to create a Model class, with some model fields and some other fields taking their data from external data sources. The point is that I would like this model to be exploited the same way as another model by ModelForm for instance. I mean if I redefine "objects" Manager of the model by specifying the actions to get the datas for special fields (those who may not be linked to datas from the database), would the modelForm link the input with the fields not attached to the database ? Similar question about related objects. If I have a Model that has a relation with that special Model, can I get this Model instances through the classic way to get related objects (with both the classic model fields and the non-database fields) ?
Please tell me if I'm not clear, I'll reformulate.
Thanks.
EDIT: I tried to make a Model with custom fields, and then override the default Manager and its functions: all, get, ... to get objects like it would be with classical Model and Manager, it works. However, I don't use QuerySet, and it seems that the only way to get ModelForm, related objects and the admin functionnalities, working with it, is to build the QuerySet properly and let it being returned by the manager. That's why now I'm wondering if it's possible to properly and manually build a QuerySet with data got from external sources, or tell django-admin, model forms and related objects to take care of another class than queryset on this Model.
Thanks
The way is to define custom methods:
Define custom methods on a model to add custom "row-level"
functionality to your objects. Whereas Manager methods are intended to
do "table-wide" things, model methods should act on a particular model
instance.
This is a valuable technique for keeping business logic in one place
-- the model.
I have now a partial solution. I override the Manager and in particular its all() and get() functions (because I only need those functions for now). all() returns a queryset in which I added the result of some logics that give me objects build from external datas (taken through xmlrpc in my case). I added those objects to the qs through _result_cache attribute.
I think it's not clean and in fact my Model is now a custom Model and I don't have any database field. I may use it to fill database Models... However I can use it the same way as classic models: MyModel.objects.all() for example.
If anyone has another idea I'd really appreciate.
Regards