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.
Related
Let us say in my models for a django app, I have three models, each with many to many relationship (this is a toy example).
class User(models.Model):
permissions_group = models.ManyToManyField(Group)
class Group(models.Model):
permissions_area = models.ManyToManyField(Area)
class Area(models.Model):
#other irrelevant field data...
pass
I would like to have a field on my User model, that expressed the relationship between users and Areas, which is an implicit many-to-many model (that is to say I don't define additional relations which create additional tables in the database, I use the relationship which goes through groups).
I have considered using a custom manager, but that doesn't seem to allow the kind of relationship filtering that one sees with a standard RelatedField manager; I could simply set a decorated property on the class:
class User(models.Model):
#property
permissions_areas(self):
return Area.objects.filter(group__in=self.permissions_groups.all())
But that seems clunky, and doesn't use any django conventions. Is there a conventional way to do this in django using Django's tooling (custom managers or something similar to RelatedManager) which I am missing?
You can just use two underscores to look through a relation, so:
class User(models.Model):
#property
permissions_areas(self):
return Area.objects.filter(group__user=self).distinct()
The .distinct() is useful if a User can belong to multiple groups that have access to this area. Without .distinct() it would return that Area for each group that has permission to that area and where the user belongs to.
I want to insert a many-to-many relationship into some models, without having to completely rewrite the models.
For example, consider the django User model and a model Foo from a third-party module I've installed.
If I 'owned' Foo I could just do:
class Foo(models.Model):
users = models.ManyToMany(User)
Then, if I wanted to add a Foo to user, or vice versa I could do:
my_user.foo_set.add(my_foo)
my_foo.users.add(my_user)
But I don't 'own' either code, and I want to inject this relationship, so I can do the above.
Now, if I wanted I could even do a through relationship through a model I made and and put that on either side, but that still requires altering the models.
Now, behind the scenes it looks like django many-to-many relationships are models (they definitely have tables), is it possible to make this code:
class FooUserRelationship(models.Model):
foo = ForeignKey(Foo)
user = ForeignKey(User)
Act just like a many-to-many relationship?
you can use proxy models. Here person is a 3rd party model and Myperson is a your model modifying extra attributes to the main models. for more details https://docs.djangoproject.com/en/1.9/topics/db/models/#proxy-models
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class MyPerson(Person):
users = models.ManyToMany(User)
class Meta:
proxy = True
The cleanest way i can think of is to provide a middle class (or you could subclass which would provide the almost the same queries) with a onetoone to one side and then many to many
class FooUser(models.Model):
user = OneToOneField(AUTH_USER_MODEL)
foo = ManyToMany(Foo)
my_user.foouser.foo_set.add(my_foo)
my_foo.foousers.add(my_user.foouser)
Now I admit that this isn't the cleanest way of doing things since it would involve a further SQL join when retrieving results, but it does keep in tact your link and provides a way to modify as you please.
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 have two models and want to set a relation to them.
class ModelA(models.Model):
id = models.IntegerField(primary_key=True) # DB => PK, AI, NN
name = models.CharField(max_length=50)
...
class ModelB(models.Model):
modelA = models.OneToOneField("ModelA", primary_key=True)
description = models.CharField(max_length=255)
...
So I have a relationship between the two models. Is it possible to add a member to ModelA which stores the relation to ModelB without saving this relation to the database?
I would call it a dynamically created relation or something. Any hints oder suggestions how to let both models know each other?
I think it would be benefiting if the relation on one model can be done dynamically. Otherwise I'll get some trouble storing the models because one of the IDs won't be stored if I save one of the models.
I want to have the relation on both models so I can easily use the models as inline in django-admin.
regards
The reverse relation in Django is created by default.
To get the ModelA you will use:
ModelA.objects.filter(modelb__pk = 1)
You will find more details here:
https://docs.djangoproject.com/en/dev/topics/db/queries/
Django ORM will save ModelA first, then ModelB, in order to maintain data integrity in the DB.
Django can try saving multiple items in one transaction, and this way, if you cancel it, nothing will be saved, but this is possible in shell or in Python code. Over HTTP you can't maintain a transaction over several queries so far.
If you need to show model A as inline of model B, you need a custom admin interface, not new fields/models. I can't tell how to write custom admin widgets. I did do a similar thing with custom editor views & templates & Javascript. I stored the unsaved models in request.session.
I want to apply the "ordering" Meta option to the Django model User from django.contrib.auth.models. Normally I would just put the Meta class in the model's definition, but in this case I did not define the model. So where do I put the Meta class to modify the User model?
This is how the Django manual recommends you do it:
You could also use a proxy model to define a different default ordering on a model. The standard User model has no ordering defined on it (intentionally; sorting is expensive and we don't want to do it all the time when we fetch users). You might want to regularly order by the username attribute when you use the proxy. This is easy:
class OrderedUser(User):
class Meta:
ordering = ["username"]
proxy = True
Now normal User queries will be unorderd and OrderedUser queries will be ordered by username.
Note that for this to work you will need to have a trunk checkout of Django as it is fairly new.
If you don't have access to it, you will need to get rid of the proxy part and implement it that way, which can get cumbersome. Check out this article on how to accomplish this.
Paolo's answer is great; I wasn't previously aware of the new proxy support. The only issue with it is that you need to target your code to the OrderedUser model - which is in a sense similar to simply doing a User.objects.filter(....).order_by('username'). In other words, it's less verbose but you need to explicitly write your code to target it. (Of course, as mentioned, you'd also have to be on trunk.)
My sense is that you want all User queries to be ordered, including in third party apps that you don't control. In such a circumstance, monkeypatching the base class is relatively easy and very unlikely to cause any problems. In a central location (such as your settings.py), you could do:
from django.contrib.auth.models import User
User.Meta.ordering = ['username']
UPDATE: Django 1.5 now supports configurable User models.
You can either subclass User:
class OrderedUser(User):
class Meta:
ordering = ['-id', 'username']
Or you could use the ordering in ModelAdmin:
class UserAdmin(admin.ModelAdmin):
ordering = ['-id', 'username']
# unregister user since its already been registered by auth
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Note: the ModelAdmin method will only change the ordering in the admin, it won't change the ordering of queries.
Contact the author and ask them to make a change.