django check if a model table has a object - python

i have a model like bellow .
class User(BaseModel,DjangoUser):
uuid = models.CharField(max_length=100, blank=True)
realname = models.CharField(max_length=100, blank=True)
followers = models.ManyToManyField('self', through='FollowRelationship', symmetrical=False, related_name='followed_by')
def follow(self, person):
relationship, created = FollowRelationship.objects.get_or_create(from_person=self,to_person=person)
return created
def unfollow(self, person):
fs = FollowRelationship.objects.filter(from_person=self,to_person=person)
if fs is not None:
fs.delete()
return True
return False
class FollowRelationship(models.Model):
from_person = models.ForeignKey(User, related_name='from_user')
to_person = models.ForeignKey(User, related_name='to_user')
follow_time = models.DateTimeField(default=datetime.datetime.now)
if i have two uses A and B , i use A in B.followers.all() to check if A is following B .
is it good to do this , if B.followers have 10000000 objects , is it a good way to do this ?
another question is that if i do follow a User in my (android) application , the A in B.followers.all() will return false for sometime and return true . if i restart the django server , it will become true immediately。 what's the problem ?

From documentation it seems .exists() is more appropriate and faster.
You can check as
if B.followers.filter(from_person=A).exists():
For 2nd question, it might be django queryset caching issue. Is it in some view?

Related

Django: how to use .filter( ) method in django?

I am trying to display quiz only for users that are registered in a particular course, i.e if a user is registered in a Frontend Crash Course i want them to see only the quiz related to that course they are registered in, and not all the quiz from the db.
i have a model UserCourse where i am storing all the courses a user have enrolled in, when i try filtering by that models while user_course is get like this below
user_course = UserCourse.objects.get(user=request.user)
quizzes = Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
i get this error get() returned more than one UserCourse -- it returned 3! Now i have changed .get() to .filter() like this
user_course = UserCourse.objects.filter(user=request.user)
quizzes = Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
i then get this error The QuerySet value for an exact lookup must be limited to one result using slicing.
What is the right way to write this query.
models.py
class UserCourse(models.Model):
user = models.ForeignKey(User , null = False , on_delete=models.CASCADE)
course = models.ForeignKey(Course , null = False , on_delete=models.CASCADE, related_name="usercourse")
class Quiz(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="quizzes")
title = models.CharField(max_length=255)
course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True, related_name="quizzes")
date = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True)
user_course = models.ForeignKey(UserCourse, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.title
The Problem in the Second Line
user_course = UserCourse.objects.filter(user=request.user)
quizzes=Quiz.objects.filter(course__usercourse=user_course).annotate(questions_count=Count('questions'))
remember that when You are using filter you get QuerySet not one object
if you want to return the quizes those related to user_course_queryset you can use __in filter
print(user_course) # print it to understand more
quizzes=Quiz.objects.filter(course__usercourse__in=user_course)
this will Return every Quiz Related to the QuerySet objects

Checking if relationship exists with query

I am trying to check whether or not a following relationship exists using a query. First, I get all of the followers the user has and then I check whether or not the user follows those followers. Here are my models:
class Following(models.Model):
target = models.ForeignKey('User', related_name='followers', on_delete=models.CASCADE, null=True)
follower = models.ForeignKey('User', related_name='targets', on_delete=models.CASCADE, null=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{} is followed by {}'.format(self.target, self.follower)
class User(AbstractBaseUser):
username = models.CharField(max_length=15, unique=True)
email = models.EmailField(max_length=100, unique=True)
I am using the Django Rest-Framework so I go to the specific URL to get the information I need. After going to the URL, the output is expected. I get all the followers the user has.
views.py
class GetFollowersView(ListAPIView):
serializer_class = FollowingSerializer
def get_queryset(self):
requested_user = get_requested_user(self)
return User.objects.filter(targets__target=requested_user).order_by('-targets__created_at'). \
annotate(is_following=Count('followers__follower', filter=Q(followers__follower=requested_user), distinct=True))
def get_requested_user(self):
filter_kwargs = {'username': self.kwargs['username']}
return get_object_or_404(User.objects.all(), **filter_kwargs)
serializers.py
class FollowingSerializer(serializers.ModelSerializer):
is_following = serializers.IntegerField()
class Meta:
model = User
fields = ('id', 'username', 'follower_count', 'following_count', 'is_following')
However, the problem is in the is_following annotation. I'd like to see whether or not the user follows each specific follower. If they follow that follower, then is_following should be 1 if not, then it is a 0. I'm getting incorrect results in is_following is there a way I can check if the user follows each specific follower?
If you have Django Debug Toolbar installed and you check the query for your current filter/annotate, this is what it shows (for a single user)
SELECT "user"."id", "user"."username", "user"."email",
COUNT(DISTINCT T4."follower_id") AS "is_following" FROM "user"
INNER JOIN "following" ON ( "user"."id" = "following"."follower_id" )
LEFT OUTER JOIN "following" T4 ON ( "user"."id" = T4."target_id" )
WHERE "following"."target_id" = 4 GROUP BY "user"."id", "user"."username",
"user"."email", "following"."created_at" ORDER BY "following"."created_at"
DESC
However to get the count of the users the chosen user follows, you really want something like this
SELECT ue."id", ue."username", ue."email", COUNT(DISTINCT fe."target_id") AS
"is_following" FROM "user" u inner JOIN "following" fe ON ( u."id" =
fe."follower_id" ) inner join user ue on fe.target_id = ue.id and u.id = 4
GROUP BY ue."id", ue."username", ue."email"
I don't think it is possible to combine both the followers and the followee in the same query like you have done. You could possibly find the intersection and then proceed from there...Something like this..
def get_queryset(self):
username = self.request.query_params.get('username', None)
requested_user = models.User.objects.get(username=username)
following_me = models.User.objects.filter(targets__target=requested_user).order_by('-targets__created_at')
i_follow = models.User.objects.filter(followers__follower=requested_user).order_by('-followers__created_at')
common = following_me & i_follow
### Set is_following for common as 1, all others as 0.
#......
#......
return following_me
Why not use an M2M relationship? Seems like this could be simple:
from django.db import models
class User(models.Model):
name = models.CharField(max_length=200)
followers = models.ManyToManyField('User')
#property
def follower_count(self):
# How many people follow me
return len(self.followers)
#property
def followee_count(self):
# How many people I follow
return len(self.user_set.all())
And you can modify the get_queryset() to only find followers:
User.objects.filter(followers__contains=self.request.user)
Does this help?

How to get objects from db under multiple constraints?

I'm trying to figure out how to get particular set of objects from database in Django efficiently.
I can do this using nested loops but I think that it's not a best idea.
I have models Language and UserProfile which has a property method verified_languages which returns a set of Language objects for this UserProfile.
What I want exactly is to create a static method of Language model called get_to_languages(language) which returns a set of all languages of all UserProfiles if these UserProfiles has language attribute in verified_languages property method.
So if there were there these Users -
1st. user:
name = 'Peter'
userprofile.verified_languages = ['english','german','arabic','french']
2nd. user:
name = 'Evgen'
userprofile.verified_languages = ['german','arabic','spanish']
3rd. user:
name = 'Anton'
userprofile.verified_languages = ['russian','arabic','italian']
And I call method get_to_languages(Languages.objects.get(name='german'))
It would return a set of Evgen's and Peter's languages because they know german.
Is it possible to do this using filter?
My old solution:
#staticmethod
def get_languages_to(language):
userprofiles = UserProfile.objects.all()
result = set()
for up in userprofiles:
if language in up.languages_verified:
result.update(up.languages_verified)
result.remove(language)
return list(result)
USERPROFILE:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='userprofile', help_text=_('Related user'))
date_of_birth = models.DateField(null=True, blank=True, help_text=_('Date of birth'))
telephone = models.CharField(max_length=40, null=True, blank=True, help_text=_('Your telephone number'))
IBAN = models.CharField(max_length=40, null=True, blank=True, help_text=_('Bank account unique number'))
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
MARITAL_STATUS_CHOICES = (
('single', 'Single'),
('married', 'Married'),
('separated', 'Separated'),
('divorced', 'Divorced'),
('widowed', 'Widowed'),
)
marital_status = models.CharField(max_length=40, choices=MARITAL_STATUS_CHOICES, null=True, blank=True)
HOW_DO_YOU_KNOW_ABOUT_US_CHOICES = (
('coincidence', u'It was coincidence'),
('relative_or_friends', 'From my relatives or friends'),
)
how_do_you_know_about_us = models.CharField(max_length=40, choices=HOW_DO_YOU_KNOW_ABOUT_US_CHOICES, null=True,
blank=True)
is_translator = models.BooleanField(default=False)
language_levels = models.ManyToManyField('LanguageLevel', blank=True, related_name='translators')
rating = models.IntegerField(default=0)
number_of_ratings = models.BigIntegerField(default=0)
#property
def languages(self):
"""
Returns: all languages of current user include not-verified ones
"""
return [x.language for x in self.language_levels.all()]
#property
def languages_verified(self):
"""
Returns: verified languages of current user
"""
return [x.language for x in self.language_levels.exclude(level__name='unknown')]
def passive_skill(self, language):
"""
True if user has at least passive skill (lowest level) of the language
Args:
language: Language object
Returns: Bool
"""
if language in self.languages_verified:
return True
return False
Well, I think it could be done this way: first, get all LanguageLevel that contains current language and their level_name is not unknown, then get all userprofiles from the result LanguageLevel. In the end, get all languages linked to these userprofiles(apparently it's untested, but please try it out):
language_levels = LanguageLevel.objects.filter(language=language) \
.exclude(level__name='unknown')
userprofiles = UserProfile.objects.filter(language_levels__in=language_levels)
all_languages = profiles.values_list('language_levels__language',
flat=True).distinct()
Note that the __in is very inefficient but that's if you don't have huge amount of records it should be OK. Just pay attention to the performance and see if that goes well.

Create another model objects in django admin within a for loop

I am completely new to django and was a php coder previously, so please bear with me if i am being dumb.
I have three models defined in my app, Comprehension, Question, Answer. Each comprehension has multiple questions and answers defined as 'inline' in the Comprehension model. Questions are input directly by the admin, but answers would added automatically from the comprehension.
What I want to achieve is, to split the comprehension in to sentences and add each sentence as an answer object with foreignkey of the current comprehension.
I am trying to override the save method in Comprehension model. But when I click save, it gives an instance error
Cannot assign "23L": "Answer.ComprehensionAnswer" must be a "Comprehension" instance.
How do I assign/create and instance here ? or am I following a wrong approach. If so, kindly guide me to the right approach.
Following are the contents of models.py
class Question(models.Model):
QuestionText = models.CharField(max_length=500, verbose_name='Question Text')
QuestionTypeID = models.ManyToManyField(QuestionType, verbose_name='Question Type')
ComprehensionQuestion = models.ForeignKey(Comprehension, verbose_name='comprehension')
QuestionRemarks = models.CharField(max_length=500, verbose_name='remarks', null=True, blank=True)
LastUpdate = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.QuestionText
def was_published_recently(self):
return self.LastUpdate >= timezone.now() - datetime.timedelta(1)
class Answer(models.Model):
AnswerText = models.CharField(max_length=500, verbose_name='Answer Text')
AnswerTypeID = models.ManyToManyField(AnswerType, verbose_name='Answer Type')
ComprehensionAnswer = models.ForeignKey(Comprehension, verbose_name='Comprehension', null=True, blank=True)
AnswerRemarks = models.CharField(max_length=500, verbose_name='Remarks')
LastUpdate = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.AnswerText
class Comprehension(models.Model):
ComprehensionTitle = models.CharField(max_length=100, verbose_name='Comprehension Title')
ComprehensionsText = models.TextField(verbose_name='Text')
ComprehensionsRemarks = models.CharField(max_length=400, verbose_name='Remarks for this Comprehension', null=True, blank=True)
LastUpdate = models.DateTimeField("Last Updated", auto_now=True)
def __unicode__(self):
return self.ComprehensionTitle
def was_published_recently(self):
return self.LastUpdate >= timezone.now() - datetime.timedelta(1)
def save(self, *args, **kwargs):
#overrides the default save function to split the comprehension paragraph into sentences and adds them as probable answers
AnswerList = self.ComprehensionsText.split("u'\u0964'")
for sentence in AnswerList:
p = Answer.objects.create(AnswerText = sentence, ComprehensionAnswer = self.pk)
super(Comprehension, self).save(*args, **kwargs)
Content inside admin.py
class ComprehensionAdmin(admin.ModelAdmin):
form = ComprehensionForm
fieldsets = [
('Main', {'fields': ['ComprehensionTitle','ComprehensionsText']}),
('Additional Info', {'fields': ['ComprehensionsRemarks'], 'classes': ['collapse']}),
]
inlines = [QuestionInline, AnswerInline]
list_display = ('ComprehensionTitle', 'LastUpdate')
list_per_page = 10
class QuestionInline(admin.TabularInline):
model = Question
extra = 2
class AnswerInline(admin.TabularInline):
model = Answer
extra = 2
admin.site.register(Question)
admin.site.register(Answer)
admin.site.register(Comprehension, ComprehensionAdmin)
I have also followed the approach mentioned on this page. But, blank about how to create the objects in commit condition using the foreignkey of Comprehension model.
You should use self instead of self.pk and note that self refers the current object.
p = Answer.objects.create(AnswerText = sentence, ComprehensionAnswer = self)
From the traceback, it clearly shows that, ComprehensionAnswer attribute of Answer model expects Comprehension model's object. But you're passing the id of that object.

Selecting data from few relational tables based on few conditions in Django

I'm using Django 1.6 with Python 2.7 and I have few related models:
# keys/models.py
class Key(models.Model):
user = models.ForeignKey('auth.User')
is_valid = models.BooleanField()
# entities/models.py
class Entity(models.Model):
user = models.ForeignKey('auth.User')
key = models.ForeignKey('keys.Key')
active = models.BooleanField(default=False)
# profile/models.py
class Profile(models.Model):
user = models.ForeignKey('auth.User')
profile_id = models.PositiveIntegerField(null=True, blank=True)
Is it possible to make a single-line query which would check these conditions:
Key.is_valid must be True
Entity.active must be True
Profile.profile_id must not be null (or None)
The only thing I can pass to that query is request.user.
if you are wanting to get Entity objects:
objects = Entity.objects.filter(active=True,
key__is_valid=True,
user__profile__profile_id__isnull=False)
I think that this is what you need:
Check entity:
entity = Entity.objects.filter(active=True, key__is_valid=True, user=request.user)
Check Profile
profile = Profile.objects.filter(user=request.user, profile_id__isnull=False)

Categories