Django Models Generic Relations - python

I'm confused with generic relationships in Django.
I have a comment model, and I want both Workflow and WorkflowItem models to be able to have multiple comments.
If I do:
class Workflow(models.Model):
comments = models.ManyToManyField(Comment)
class WorkflowItem(models.Model):
comments = models.ManyToManyField(Comment)
then what do I put in the comment class to link the comment to one of these based on which it is or do I need generic relationships?
Also say I want to put members who are part of the Workflow model, do i do
class Workflow(models.Model):
comments = models.ManyToManyField(Comment)
members = models.ManyToManyField(Person)
or something else?

As you mentioned that you need to link comment back to either Workflow/WorkflowItem, I believe you can structure your models as below
class Workflow(models.Model):
members M2M field
class WorkflowItem(models.Model):
fields
class Comment(models.Model):
name_of_your_generic_fk(Can be either Workflow/WorkflowItem or any content type for that matter)
fields
Using models structure like this you can trace from comment if it was made on Workflow/WorkflowItem.
You can obviously devise a better solution if you put more thought into it!! :)

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 Inlineformset with editable Foreign Key Relation

I'm trying to create a formset of related objects, where the relation itself is also an editable field.
Let's say we have a models.py like the one below.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=45)
class Book(models.Model):
name = models.CharField(max_length=45)
author = models.ForeignKey(Author)
Is there a good, pythonic way to create a formset of all Books by a certain Author, and be able to change the Author of any of those books? This would be a particularly useful way to fix any errors in the foreign key relations.
My first instinct was that inlineformset would solve this for me, but I can't seem to get the Author of each book to be an editable field, even when I use custom forms.
using modelformset_factory will do the trick. (pulled from my comments here for completeness of the systems question/answer model)

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.

Setup Django Blog Comments

If I wanted to setup comments for a blog in Django, and I wanted people to be able to reply to comments (like a normal blog), meaning each comment would have to know if it's a comment on another comment or not, would I set the model fields like this?
from django.db import models
from django.contrib.auth.models import User
class Comment(models.Model):
post = models.ForeignKey(Post)
user = models.ForeignKey(User)
text = models.TextField()
date = models.DateTimeField()
reply_to = models.ForeignKey(Comment, blank=True, null=True)
Is that correct? And how would I display them in a template?
Writing a hierarchical comments application seems too easy at first look but believe me it is not that simple. There are too many edge cases and security issues. So if this is a real project i would suggest you to use disqus, any other hosted solution or (now deprecated) comments framework.
On the other hand if you are just trying to learn how things done or playing around, your code seems fair enough so far. But you should consider Django's built-in content types framework instead of a direct foreign key relationship. That way you can relate a comment object to any other object. (a blog post or another comment). Take a look at comment frameworks models.py and you will see it.
class BaseCommentAbstractModel(models.Model):
"""
An abstract base class that any custom comment models probably should
subclass.
"""
# Content-object field
content_type = models.ForeignKey(ContentType,
verbose_name=_('content type'),
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField(_('object ID'))
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
Also take a look at RenderCommentListNodein comment framework template tags. You should write a recursive function in order to get and display hierarchical comments.
You have to consider cases like:
What will happen if a user deletes a comment?
How should we delete comments? Should we actually remove it from database or should we set an attribute like deleted
How should we deal with permissions and level of user access?
If we let anonymous users to comment, what information do we need from them.
How to check human validation? Is captcha enough?
Happy hacking.

Creating several profile classes in django

I'm getting started with django and I'd like to extend the basic django.contrib.auth.models.User class to create my own site profile(s). Here is described how to do it, got that.
As far as I've understood it, you can only specify a single class as AUTH_PROFILE_MODULE in your settings.py.
Now, if I create an extension class of my profile class like this
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
somefield = models.CharField()
class UserProfileExtended(UserProfile):
extrafield = models.CharField()
then I cannot make both of them profile classes, right?
(I know, in this case you'd just add the extrafield to the superclass and drop the UserProfileExtended entirely. Just imagine you have so many fields in UserProfileExtended that you really want to split them up)
Thanks for your help!
There can be only one profile class. I guess I don't understand the scenario where you would want to split them up. In any case,
AUTH_PROFILE_MODULE = "UserProfileExtended"
should handle the inheritance correctly for the simple example you give.

Categories

Resources