DRF serialisation issue: combining django-simple-history and django-polymorphic - python

I am using regular Django models but have now started to incorporate a polymorphic model into my DRF REST API project using django-polymorphic and rest-polymorphic. I am also using django-simple-history to track changes to entries in my database. This all works fine for normal models and polymorphic models without a HistoricalRecords() field, but errors when trying to interact with any polymorphic model that has a HistoricalRecords() field:
django.core.exceptions.FieldError: Cannot resolve keyword 'material_ptr_id' into field.
In my serialiser for the polymorphic models, I use the following technique to serialise the history field:
class HistoricalRecordField(serializers.ListField):
child = serializers.DictField()
def to_representation(self, data):
return super().to_representation(data.values())
class ItemSerializer(serializers.ModelSerializer):
history = HistoricalRecordField(read_only=True)
class Meta:
model = Item
fields = ('history')
Is there a way to exclude the material_ptr_id field from being taken into account by the serialiser as it is not part of the parent model but only the child models? Or are there any obvious other mistakes I am making? Thanks for any help with this.

Related

Django Like mechanism. Database performance question

I have CustomUser model and Post model. I consider adding a lightweight like mechanism to the posts.
What comes to my mind is defining a Like model in such fashion to connect the models to each other:
class LikeFeedback(models.Model):
likingUser = models.ForeignKey(CustomUser)
post_liked = models.ManyToManyField(Post)
But this design produces a new row in the database with each like.
Another option is to define CustomUser and Post models in a way that:
class Post(models.Model):
...
users_liked = models.ManyToManyField(CustomUser)
class CustomUser(models.Model):
...
posts_liked = models.ManyToManyField(Post)
I am not sure if this approach creates a new row or uses a different indexing mechanism, but it looks tidier.
In terms of DB performance what approach is the fastest? Do I need to define the ManyToMany connection in both models to speed up DB processes? Because 15 posts are to be displayed on the webpage at once and and with every post it is necessary to check if the visitor already liked the note. Also, with each like and takeback a write operation is to be performed on the DB.
I am not sure if this approach creates a new row or uses a different indexing mechanism, but it looks tidier.
A ManyToManyField will create an extra table called a junction table [wiki] with ForeignKeys to the model where you define the ManyToManyField, and the model that you target with the ManyToManyField.
You furthermore only need one ManyToManyField, otherwise you make two relations that act indepdently. You thus model this as:
from django.conf import settings
class Post(models.Model):
# ...
likes = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name='liked_posts'
)
class CustomUser(models.Model):
# ...
# no ManyToManyField to Post
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

django-parler translations for abstract model

My django app must be translatable, static pages and models too. For translating models I'm using django-parler app. This works fine, but for simple models, I mean, models that doesn't inherits from an abstract model class.
Let's say that we have a Vehicle abstract model
class Vehicle(TranslatableModel):
translations = TranslatedFields(
description=models.CharField(max_length=100)
)
class Meta:
abstract = True
and a child model which is Car:
class Car(Vehicle)
"""..."""
This raised me this error: TypeError: Can't create TranslatedFieldsModel for abstract class Vehicle.
I'd like still using django model inheritance. So, what can I do for translating my models using django-parler, it support translations for abstract models or I'll need to use another app to achieve this, in that case any suggestion on any?
The problem is, parler implicitly creates an extra db table for the translations which has a ForeignKey to the model that the translated fields are declared on. You cannot have a FK to an abstract model because it does not have its own db table. What if you have two models subclassing this abstract model? Which table is the translation table's FK pointing to?
You could try to implement the translatable fields outside of your model if you want to share the same translatable fields across models and still be relatively DRY:
vehicle_translations = TranslatedFields(
description=models.CharField(max_length=100)
)
class Car(TranslatableModel):
translations = vehicle_translations
The best solution is to use TranslatedField as explained in the docs: https://django-parler.readthedocs.io/en/latest/api/parler.fields.html#the-translatedfield-class

through model for an Abstract model

I have an Abstract model:
class Distributor(models.Model):
class Meta:
abstract = True
and 2 models which inherit it:
class DistributorGroup(Distributor):
pass
class DistributorPerson(Distributor):
pass
also I have a llink model:
class Link(models.Model):
distributors_persons = models.ManyToManyField(
'people.DistributorPerson', blank=True, related_name='distributors_persons_of_links')
distributors_groups = models.ManyToManyField(
'groups.DistributorGroup', blank=True, related_name='distributors_groups_of_links')
A link can have a relation with one of the distributors. I accomplished this behavior by adding 2 m2m and setting blank=True to both.
Now I realized that I need a through model to connect Distributors and Link. But as through model can't have an abstract model as a foreign key I don't know what to do. Do I need to create 2 separate through models for DistributorPerson and DistributorGroup or there is a way to accomplish this with 1 through model. Also I don't know if my 2 m2m in Link model are a proper way to accomplish the behavior that I want.
So I would like to know what is the way to organize these m2m models with an abstract model.
The first question is whether DistributorPerson and DistributorGroup really need to be separate tables. If they're very similar it might make sense to just use a single table. (For example, if you were modeling phone numbers you probably wouldn't use separate Home, Work, and Mobile tables, you'd instead use a single table with a type field.)
(And note that you can use proxy models to allow different Django models to share the same database table.)
If you do need separate tables, then you might look at GenericForeignKey. This is a mechanism to allow foreign keys to reference objects from different model types. In your case this might look like:
class DistributorGroup(Distributor):
distributor_links = GenericRelation(DistributorLink, related_query_name="distributor_groups")
class DistributorPerson(Distributor):
distributor_links = GenericRelation(DistributorLink, related_query_name="distributor_persons")
class Link(models.Model):
pass
class DistributorLink(models.Model):
link = models.ForeignKey(Link);
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
See the documentation on generic relations for examples and more detail.
Finally, if all else fails, you could indeed create two separate M2M tables for the two kinds of relation.
Note that none of this really has anything to do with abstract models. Abstract models are just a mechanism for code reuse in Django, they don't affect the tables or the queries you run on them.

Django REST framework serializing model combinations

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.

Django 1.5 select_related defer with multi table inheritance

EDIT:
I fixed a few typos below
I added a zip file to a small app to demonstrate this problem here. You can download it and run python manage.py testselectrelateddefer after you syncdb and migrate.
I added a couple of observations below
I fix I am having a multi-table inheritance model as following:
class Image(models.Model):
# other fields are removed for simplicity
image = models.ImageField(upload_to="image")
class ItemImage(Image):
# other fields are removed for simplicity
display_name = models.CharField(max_length=50)
I want to query this model and defer the image field when I don't need the image (which is in the parent model). My container model looks somewhat like this:
class Item(models.Model):
item_image = models.OneToOneField(ItemImage)
The query looks like this:
test.models.Item.objects.select_related('item_image').defer("item_image__image").get(pk=1)
Django is throwing an error saying:
ValueError: u'image_ptr_id' is not in the list.
Django does not throw an error if I query for the field that is not in the parent model:
test.models.Item.objects.select_related('item_image').defer("item_image__display_name").get(pk=1)
Do you know how to fix this issue?
Observations:
As I mentioned above, this only happens if the deferred field is in the parent model; it does not happen if the deferred field is in the child model.
It does not matter if the parents field have any extra field.

Categories

Resources