I wrote a quest system for an online game. My quests are serialized into json objects for a JavaScript client that fetches those quests then from a REST backend (I use django RestFramework)
Now I'm wondering on which class or django model I should put the "behaviour" that belongs to the data.
I stored the data that belongs to a quest in several separate models:
A model QuestHistory: with models.Fields like Boolean completed, and Datetime started where I put the information belonging to a specific user (it also as a field user).
Then I have a model QuestTemplate : The part that is always the same, fields like quest_title and quest_description
I also have a model Rewards and model Task and TaskHistory that are linked to a quest with a foreign Key field.
To combine this information back to quest I created a pure python class Quest(object): and defined methods on this class like check_quest_completion. This class is the then later serialized. The Problem with this approach is that It becomes quite verbose, for example when I instantiate this class or when I define the Serializer.
Is there a python or django "shortcut" to put all fields of a django model into another class (my Quest class here), something similar to the dict.update method maybe?
Or should I try to put the methods on the models instead and get rid of the Quest class?
I have some other places in my game that look very similar to the quest system for example the inventory system so I'm hoping for a more elegant solution.
You should put the methods of the Quest class on the model itself and get rid of the Quest class.
Related
Can we say that Django models are considered dataclasses? I don't see #dataclass annotation on them or on their base class model.Models. However, we do treat them like dataclasses because they don't have constructors and we can create new objects by naming their arguments, for example MyDjangoModel(arg1= ..., arg2=...).
On the other hand, Django models also don't have init methods (constructors) or inherit from NamedTuple class.
What happens under the hood that I create new Django model objects?
A lot of the magic that happens with models, if not nearly all of it, is from its base meta class.
This can be found in django.db.models.ModelBase specifically in the __new__ function.
Regardless of an __init__ method being defined or not (which actually, it is as per Abdul's comment), doesn't mean it can or should be considered a dataclass.
As described very eloquently in this SO post by someone else;
What are data classes and how are they different from common classes?
Despite django models quite clearly and apparently seeming to have some kind of data stored in them, the models are more like an easy to use (and reuse) set of functions which leverage a database backend, which is where the real state of an object is stored, the model just gives access to it.
It's also worth noting that models don't store data, but simply retrieves it.
Take for example this simple model:
class Person(models.Model):
name = models.CharField()
And then we did something like this in a shell:
person = Person.objects.get(...)
print(person.name)
When we access the attribute, django is actually asking the database for the information and this generates a query to get the value.
The value isn't ACTUALLY stored on the model object itself.
With that in mind, inherently, django models ARE NOT dataclasses. They are plain old regular classes.
Django does not work with data classes. You can define a custom model field. But likely this will take some development work.
I'm programming an online game with a JavaScript client and I use Django REST framework for the backend. I have written a quest system for it.
My quests objects are dynamically created from a django model QuestTemplate which stores information like the Quest desription and the titel (the part that is the same for every user); and another model QuestHistory where I put the information about the state of quest for a certain user: so it has fields like user and completed. They also have some nested objects: Tasks and, Rewards which are created in a similar way to the the Quest objects.
I added a pure python class Quest that combines all the fields of those models, and then I wrote a Serializer for this class. The drawback is that I have to define all the fields again in the QuestSerializer
I have seen that for the ModelSerializer you can use a inner class Meta where you specifiy the model and . Is there also a way to do this with a normal python class instead of a model (with my Quest class).
http://www.django-rest-framework.org/api-guide/serializers#specifying-nested-serialization
Or:
Is it possible to specify more than one model in this inner class, so that it takes fields from my model QuestTemplate and some other fields from my model QuestHistory?
(I'm also not sure about whether this structure makes sense and asked about it here: django models and OOP design )
In the class Meta of the ModelSerializer you can specify only one Model as far as I know. However there are possibilities to add custom fields to the serializer. In your case you could maybe try with:
custom_field = serializers.SerializerMethodField('some_method_in_your_serializer')
You should add the method to your serializer like this:
def some_method_in_your_serializer(self, obj):
# here comes your logic to get fields from other models, probably some query
return some_value # this is the value that comes into your custom_field
And add the custom_field to fields in the class Meta:
class Meta:
fields = ('custom_field', 'all_other_fields_you_need')
Take a look in the documentation about SerializerMethodField for deeper understanding.
I’m quite new to Django and I’m trying to implement polymorphism inside a Django model, but I can’t see how to do. Before going on I have to say I’ve already tried django-model-utils and django-polymorphism, but they don’t do exactly what I’m looking for.
I have a model called Player, each player has a Role and each Role has different behaviours (i.e. their methods return different values):
class Player(models.Model):
username=models.TextField()
role=models.ForeignKey(Role) #Role is another model with a field called ’name'
def allow_action(self)
#some stuff
class RoleA():
def allow_action(self):
#some specific stuff
class RoleB():
pass
I want that every time I retrieve any instance of Player (in example through Player.objects.filter(…)) every instances has the allow_action() method overwritten by the custom one defined inside the specific class (RoleA, RoleB, etc…) or use the default method provided in Player if the related subclass has no method called with the same name (RoleA, RoleB, etc... are the same role name stored in Player.role.name).
CONSTRAINTS:
Since subclasses (RolaA, RoleB, etc…) do not add new field but only overwrite methods all data have to be stored inside Player’s table, so I don’t want to use Django Multi-Table Inheritance but something more similar to Proxies.
I don’t want to perform additional JOIN to determine specific subclass type since all informations needed are stored inside Player’s table.
I think that this is a standard polymorphism pattern but I don’t see how to implement it in Django using the same table for all players (I've already implemented this polymorphism but not linked to a Django model). I’ve seen Django has a kind of inheritance called “Proxy” but it doesn’t allow to make queries like Player.objects.filter(…) and get instances with method overwritten by custom ones (or at least this is what I understood).
Thanks in advance.
Disclaimer: I've not used django-polymorphic, and this code is based on 5 minutes spent scanning the docs and is entirely untested but I'll interested to see if it works:
from polymorphic import PolymorphicModel
class Role(PolymorphicModel):
name = models.CharField()
class RoleA(Role):
def allow_action(self):
# Some specific stuff...
class RoleB(Role):
pass
class Player(models.Model):
username=models.TextField()
role=models.ForeignKey(Role) #Role is another model with a field called ’name'
def allow_action(self)
if callable(getattr(self.role, "allow_action", None):
self.role.allow_action()
else:
# default action...
Now I believe you should be able to create an instance of Role, RoleA, or RoleB and have Player point to it in the foreign key. Calling allow_action() on an instance of Player will check to see if the instance of Role (or RoleA, RoleB etc) has a callable attribute allow_action() and if so, it will use that, otherwise it will use the default.
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
I'm developing kind of a social network in Django, but I don't see the way to maintain coupled my models.
I have a model User, which can comment on other Users, Pics, Pages (capitals are because they're models) via a Comment model. In order to arrange all that comments I created the Board model, that has one owner and receives all the comments addresed to that owner. The problem is I don't know how is its owner, i.e., which model does it belong to. It could be a pic's board, but also a user's one. So I end up with a model like this:
class Board(models.Model):
category = models.IntegerField()
owner_id = models.IntegerField()
I store owner's id and owner's category to be able to perform other tasks, but this solution doesn't convince me at all. A friend has advised me to use an abstract class Board, and then create a UserBoard, PicBoard, PageBoard which inherit from Board, but I think that will be useless too. I've thought about GenericRelations, but I'm not sure if that is the correct way to achieve what I'm trying. Any proposal will be listened and considered, thanks for your help :)
PS: Oh, and sorry if the title isn't very descriptive, but I couldn't figure out a better one. It's hard to explain this problem
Option 1
Create a class BoardOwner. Have all models which have a board inherit from that, and have the board have a foreignkey relationship with BoardOwner. You'll need to then scan over the various childlinks to figure out which one is the "real" child. This more fiddly, but localises all of the complexity in one class.
Option 2
Have a foreignkey from each class that has a board to the board. If you always have boards enter your system via a method on the owner (as opposed to a query on Board or elsewhere), you can have code in the owner which lets the Board know which foreign key reverse relationship to use. You'll probably want to factor that code into its own class.
Option 3
Use contenttypes: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
This wraps up this sort of thing.