Check if an object exists in another models foreignkey field - django

I have a reviewing system for Subjects. User can review a subject, and users can like that review.
class UserReview(models.Model):
subject = models.ForeignKey(Subject, blank=True, null=True)
user = models.ForeignKey(User)
review = models.TextField(null=True, blank=True)
likes = GenericRelation('Like')
class Like(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Meta:
unique_together = (('content_type', 'object_id', 'user'),)
How do I check if a user (eg UserA) exist in the likes of a user review? For now I am doing this way:
if user_review_obj.likes.filter(user=UserA).count() > 0:
// exist...
But I am hoping there is another better way.

You can use exists, however the correct usage is
if user_review_obj.likes.filter(user=UserA).exists():
# . . .

Related

How to create several ContentType fields in a Django model?

My Django model uses a Function model, i.e. a generic function in the company (e.g. : CFO).
In this model, I would like to have a field pointing to the default person who holds the function + another field pointing to a backup person in case of problem. Each of this field should be able to point to various models (both the user model + a model with people who have not signed in yet on the website)
As long as I only point to one model, it is easy :
class Function(models.Model):
function_name = models.CharField(max_length=255, blank=True) # e.g. CFO
main_user = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True, blank=True)
backup_user = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True, blank=True)
But if I want each of the two fields to point to different models, I need to use ContentType, like :
class Function(models.Model):
functionname = models.CharField(max_length=255, blank=True) # e.g. CFO
#GenericForeignKey:
content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
How to have two GenericForeignKeys in one model ? (for the main_user and for the backup_user)?
Thanks a lot for you help, I am confused on how to proceed
GenericForeginKey can take 2 positional arguments, first of them is the field name for the ForeignKey to the ContentType, second one is the field name for the object ID for the generic relation. Given that information, you can construct your generic relations like:
class Function(models.Model):
functionname = models.CharField(max_length=255, blank=True) # e.g. CFO
main_user_content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL)
main_user_object_id = models.PositiveIntegerField()
main_user = GenericForeignKey('main_user_content_type', 'main_user_object_id')
backup_user_content_type = models.ForeignKey(ContentType, on_delete=models.SET_NULL)
backup_user_object_id = models.PositiveIntegerField()
backup_user = GenericForeignKey('backup_user_content_type', 'backup_user_object_id')

How to post to HyperlinkedRelatedField in Django Rest Framework?

Here I have two models called PostComment and AnswerComment separately to handle comments in my web application. Now I need to have voting option for both Post and Answer comments. Therefore I though using Django GenericRelations here would be a good idea to continue. I have implemented all the parts and I can't use Django Rest Framework to post data with Django HyperlinkedRelatedField. I'm using rest-framework-generic-relations (link) app as DRF documentation has recommended it. It gives me following error when I try to post data.
Followings are my implementations,
Post and Answer Models,
class PostComment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
comment = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class AnswerComment(models.Model):
answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
comment = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Comment Model,
class VoteType(models.TextChoices):
EMPTY = 'EMPTY'
LIKE = 'LIKE'
DISLIKE = 'DISLIKE'
class CommentVote(models.Model):
voteType = models.CharField(max_length=10, choices=VoteType.choices, default=VoteType.EMPTY)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
voted_object = GenericForeignKey('content_type', 'object_id')
Serializer for vote (as implemented in the documentation),
class CommentVoteSerializer(serializers.ModelSerializer):
voted_object = GenericRelatedField({
AnswerComment: serializers.HyperlinkedRelatedField(
queryset=AnswerComment.objects.all(),
view_name='answercomment-detail'
),
PostComment: serializers.HyperlinkedRelatedField(
queryset=PostComment.objects.all(),
view_name='postcomment-detail'
),
})
class Meta:
model = CommentVote
fields = ['voted_object', 'voteType', 'owner']
View for vote,
class CommentVoteViewSet(viewsets.ModelViewSet):
queryset = CommentVote.objects.all()
serializer_class = CommentVoteSerializer
Urls for vote,
router.register(r'comment_vote', CommentVoteViewSet, basename='comment_vote_api')
Any help would be great. Thank you!

When an object can belong to several other objects, where does the foreign key belong?

Using Django 1.11.6 and Postgres 9.2
If I have the following models:
class RoughDraft(models.Model)
class Manuscript(models.Model):
rough_draft = models.ForeignKey(RoughDraft)
class AudioBook(models.Model):
manuscript = models.ForeignKey(Manuscript)
class Series(models.Model):
class Book(models.Model):
manuscript = models.ForeignKey(Manuscript)
series = models.ForeignKey(Series)
I want to add a Notes model to my project to allow multiple users add comments to RoughDrafts, Manuscripts, Books and AudioBooks. Further, when a RoughDraft becomes a Manuscript or Manuscript becomes a Book or AudioBook, I want the Notes to be carried forward.
Is it better to create a notes model like this:
class Notes(models.Model):
text = models.TextField()
and add a notes = models.ManyToMany(Notes) field to each of RoughDraft, Manuscript, Book, Series and AudioBook
or
class Notes(models.Model):
text = models.TextField()
rough_draft = models.ForeignKey(RoughDraft, null=True, blank=True)
manuscript = models.ForeignKey(Manuscript, null=True, blank=True)
series = models.ForeignKey(Series, null=True, blank=True)
book = models.ForeignKey(Book, null=True, blank=True)
audio_book = models.ForeignKey(AudioBook, null=True, blank=True)
Or should I create a ManuscriptNotes model, a RoughDraftNotes model, etc...
You can use a "generic key" with Django.
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Note(models.Model):
content = models.TextField()
author = models.ForeignKey(User, ...)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
This allows you to relate your Note object to any other object in your database

How do I link the User model with a Taxonomy model?

How do I link the User model with a Taxonomy model. How do add terms for a specific user and how can I retrieve them?
I'm quite new to Django so you must excuse my lack of knowledge and for not grasping the specific terminology, yet.
I have the folowing model witch extends the basic user:
class UserProfile(models.Model):
user = models.OneToOneField(User)
birthday = models.DateField(blank=True)
about_me = models.TextField(blank=True,null=True)
avatar = models.ForeignKey(Picture,blank=True, null=True)
class Meta:
db_table = 'auth_user_profile'
I also have the following taxonomy model:
class TaxonomyGroup(models.Model):
related taxonomy items"""
name = models.CharField(max_length=25, db_index=True)
slug = AutoSlugField(populate_from='name', unique = True)
def __unicode__(self):
return u'%s' %self.name
class Meta:
db_table = 'taxonomies'
ordering = ['name']
class TaxonomyItem(models.Model):
taxonomy_group = models.ForeignKey(TaxonomyGroup, db_index=True)
name = models.CharField(max_length=55, db_index=True)
slug = AutoSlugField(populate_from='name', unique = True)
def __unicode__(self):
return u'%s' %self.name
class TaxonomyMap(models.Model):
taxonomy_group = models.ForeignKey(TaxonomyGroup, db_index=True)
taxonomy_item = models.ForeignKey(TaxonomyItem, db_index=True)
content_type = models.ForeignKey(ContentType, db_index=True)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type','object_id')
objects = TaxonomyManager()
class Meta:
db_table = 'term2object'
unique_together = ('taxonomy_item', 'content_type', 'object_id')
The way I see it, you want a many-to-many relationship between the taxonomy and user models, so you can add it to UserProfile model.
class UserProfile(models.Model):
user = models.OneToOneField(User)
birthday = models.DateField(blank=True)
about_me = models.TextField(blank=True,null=True)
avatar = models.ForeignKey(Picture,blank=True, null=True)
taxonomies = models.ManyToManyField(TaxonomyItem)
Then when you are adding terms for a specific user you'll do:
taxonomy = TaxonomyItem.objects.create(taxonomy_group=<some_group>, name=<some_name>,...)
profile = user.get_profile()
profile.taxonomies.add(taxonomy)
to retrieve you can do
profile.taxonomies.all()

Django Forms for generic relationships. How to include them?

I have a Phone model that is being constantly used by many different models as a generic relationship. I have no idea how to include it in the Create/Update forms for those models… how good or bad of an idea is it to include the extra fields in a forms.ModelForm subclass… kind of like this:
###### models.py
class UpstreamContactModel(models.Model):
client = models.ForeignKey(UpstreamClientModel,
related_name='contacts')
contact_type = models.CharField(max_length=50, default='Main',
blank=True, null=True)
name = models.CharField(max_length=100, unique=True)
job_title = models.CharField(max_length=50, blank=True, null=True)
email = models.EmailField(blank=True, null=True)
skype_id = models.CharField(max_length=30, blank=True, null=True)
phones = generic.GenericRelation(Phone)
notes = models.TextField(blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
verbose_name = 'Contact'
class Phone(models.Model):
info = models.CharField('Eg. Office, Personal, etc',
max_length=15, blank=True)
number = models.CharField('Phone numbes', max_length=20)
# generic relationships so I can attach to other objects later on
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
def __unicode__(self):
return self.number
##### forms.py
class ContactForm(forms.ModelForm, BaseValidationForm):
info = forms.CharField(max_length=15)
number = forms.CharField(max_length=20)
class Meta:
model = UpstreamContactModel
def clean(self):
???
def save(self):
???
I've been trying to find out how people handles CRUD when a generic relationship is involved but I've been unsuccessful at that so far.
If you use a model form you can see what kind of form elements they use.
For content_type it will typically use a ModelChoiceField with ContentType.objects.all() as the queryset, and object_id will be a TextInput looking for the positive integer. I don't think the actual generic accessor will show up in the form if you use a model form.
If you want a more elegant solution than this I'd look into writing a custom form field or widget to handle it.
I don't think it's bad practice to add additional fields to the ModelForm as you have, in fact I think that's a good route to go about it. Overriding the save method will probably give you the functionality you desire.