Excluding existed users in the ManyToManyField - python

I am building a small BlogApp and I build a feature of adding favorite users. User can search and add the user in his favorite users list
I am now building a feature if searched user is already in another's users favorite user list then exclude the user from the result
For example :- If user_1 added user_50 in his favorite user's list. and then if user_2 searched user_50 then it will not show in the search list.
BUT when i try to exclude then it is not excluding.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
full_name = models.CharField(max_length=100,default='')
friends = models.ManyToManyField("Profile",blank=True)
email = models.EmailField(max_length=60,default='')
class FavouriteUsers(models.Model):
adder = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
favouriteUser = models.ManyToManyField(User, related_name='favouriteUser', blank=True)
views.py
def search_users_favourite(request):
q = request.GET.get('q')
exclude_this = FavouriteUsers.objects.filter(favouriteUser=request.user)
results = Profile.objects.filter(user__username__icontains=q).exclude(exclude_this)
serialized_results = []
for result in results:
serialized_results.append({
'id': result.id,
'username': result.user.username,
})
return JsonResponse({'results': serialized_results})
BUT this is showing :-
TypeError: Cannot filter against a non-conditional expression.
I have tried many times but it is still that error.
Any help would be Appreciated.
Thank You in Advance.

Try this query:
Profile.objects.filter(user__username__icontains=q, user__favouriteUser__isnull=True)
This will exclude all profiles that are already mapped in FavouriteUsers (already has been a favorite)

I think you should be doing it this way
exclude_this = FavouriteUsers.objects.filter(favouriteUser=request.user).values_list('favouriteUser__username',flat=True)
results = Profile.objects.filter(user__username__icontains=q).exclude(user__username__in=exclude_this) here, i assume you want to exclude usernames matching the entire name.
For a better answer, please attach the log of the error.

I spent hours tearing my hair out over this issue, so I wanted to post a quick response here on what is actually causing this exception:
The problem is this (pseudo code):
query = Model.objects.filter(something=value)
result = Model.objects.filter(query).first()
This won't work (apparently). Django hates it big time.
The problem is that you can't pass a QuerySet to filter or exclude.
Instead, use your QuerySet directly:
query = Model.objects.filter(something=value)
result = query.first()

Related

django URLs MultipleObjectsReturned error

I am making a simple webapp with Django. A user can have a profile, and under that profile create a blog post.
For example:
"path('profile/<int:pk>/',profile, name='profile')"
Returns the URL
"http://127.0.0.1:8000/profile/1/"
A user can then write blog posts which have the name in the URL
Example:
path('profile/<int:pk>/blog/<str:name>',Blogs, name='Blogs'),
Returns the URL
"http://127.0.0.1:8000/profile/1/blog/HelloWOrld"
However, IF two different users both name their blogs the same exact name, i get a 'MultipleObjectsReturned' Error.
I thought that by having the user PK earlier in the URL it would ensure that it would be unique, even if two blogs were called the exact same thing.
Views.py
def Blog(request, pk, name):
blog = Restaurant.objects.get(name=name)
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'user': user,
'blog': blog,
}
return render(request, 'blog/blogs.html',context)
IS there any way to work around this without using the PK of the blog as well?
And if anyone could explain why my logic was wrong and it wasn't working in the first place.
Thanks.
You need to make sure you get the blog of that name of that user. I don't know exactly how your blog models look, but it's going to be something like
user = CustomUser.objects.get(pk=pk)
blog = Restaurant.objects.get(name=name, user=user)
And on the model, use the 'unique_together' property to ensure that the combination of user and blog name are unique, otherwise these URLs aren't going to work. Having the name completely unique as in George's answer isn't necessary and would mean that users couldn't create blog posts with titles already made by another user.
You need to make name field unique, and use SlugField for this if you want to use clean url:
class Restaurant(models.Model):
name = models.CharField(unique=True, ...)
slug = models.SlugField(unique=True, ...)
...

'.....' object is not iterable in django

I have 3 models: User, Choice, Card. Each user will look at the same set of 10 cards and decides each one is important or not.
Here are how I define the classes and their relationship
In models.py:
class Choice(models.Model):
user = models.ForeignKey(User)
card = models.ManyToManyField(Card)
is_important = models.NullBooleanField()
class Card(models.Model):
card_number = models.IntegerField(primary_key=True)
content = models.TextField(null=False)
In views.py
(I try to save the choice for the card from the user. )
def listings(request):
user = request.user
choice = Choice.objects.create(user=user, is_important = True)
choice.card= Card.objects.get(1)
However, I got this error
'Card' object is not iterable
Could you please show me where the error is?
Many thanks!
You can add object against many to many field like this
card = Card.objects.create(card_number=any_number, content='abc')
choice.card.add(card)
First, it looks like you forgot pk= in your first .get() argument: Card.objects.get(pk=1)
Second, Choice.cards is a ManyToManyField that expects a list of items and not one in particular. You should set it through:
choice.card.set(Card.objects.filter(pk=1))
Please note that direct assignment with = will be deprecated from Django 1.10 and deleted in Django 2.0
.filter() will return a QuerySet (which is iterable). I think you wanted a ForeignKey instead of a M2M field, in which case your code would work (with the additional pk=).
In your function:
def listings(request):
user = request.user
choice = Choice.objects.create(user=user, is_important = True)
choice.card= Card.objects.get(1)
The following line is trying to fetch the Card object. However, we need to specify which card to be fetched.
If using an id, query it as:
choice.card= Card.objects.get(pk=1)
or else using list of ids:
choice.card = Card.objects.filter(pk__in=[12,22])
If using card_number field:
choice.card= Card.objects.get(card_number=1)
or else using list of card_numbers:
choice.card = Card.objects.filter(card_number__in=[12,22])

Filter by twice-removed ForeignKey objects

I have the following models: User, UserProfile, and SalesCompany
Relationship: Every User has a UserProfile and every UserProfile has a SalesCompany.
I need to get all Users at SalesCompanys with more than one UserProfile.
Is there a more efficient way to do it than my following solution? Some combo of annotate and traversing ForeignKeys seem to be the solution, but I'm stumped.
# get all users
all_users = User.objects.all().order_by('username')
users = []
# for each user
for user in all_users:
try:
# get profile
profile = UserProfile.objects.get(user=user)
# get count of profiles (i.e. users) at current user's company
count_users = len(UserProfile.objects.filter(company=profile.company))
# if more than one user at company (so not just current user)
if count_users > 1:
# add to users list
users.append(user)
except Exception, e:
pass
This should execute just one SQL query:
companies_with_more_than_1_user = (
Company.objects
.annotate(num_users=Count('userprofile'))
.filter(num_users__gt=1)
)
users = User.objects.filter(userprofile__company__in=companies_with_more_than_1_user)
Stuff like this is a reason to like the Django ORM, even though I'm generally ambivalent or even slightly disliking towards Django and its way of doing things.

How to delete a many to many object without deleting all objects within the relationship?

In models.py I have...
class Siteinfo(models.Model):
url = models.CharField(max_length=100)
description = models.TextField()
class Makesite(models.Model):
sitename = models.CharField(max_length=100, unique = True)
siteinfo = models.ManyToManyField(Siteinfo)
ref_id = models.ManyToManyField(RefID)
def __unicode__(self):
return u'%s' %(self.sitename)
I'm trying to delete a instance of description and replace it with another instance and still have it be associated with the same url and still be the many to many object under say. Group on.
So group1 is the site name. to create the relation I have
url = request.POST['url']
description = request.POST['description']
datsite = Makesite.objects.get(sitename=site)
datsite.siteinfo.add(Siteinfo.objects.create(url=url,description=description))
But then when I try to delete and replace the description with this bit of code it also deletes the url.
name = Makesite.objects.get(sitename=site).siteinfo.values_list('description',flat=True)[0]
Makesite.objects.get(sitename=site).siteinfo.get(description=name).delete()
I guess I could try to write some code that could get around this problem but I'd rather find a way to just delete one and add another instance in its place.
Just to be picky, you should be using forms for processing user input.
It sounds like you want to be updating an instance, not deleting and adding one nearly exactly the same.
site_info = Makesite.objects.get(sitename=site).siteinfo.get(description=name)
site_info.description = "new description"
site_info.save()
Or, more simply:
site_info = Siteinfo.objects.get(makesite__sitename=site, description=name) # only 1 query
site_info.description = "new description"
site_info.save()

How to query datastore when using ReferenceProperty?

I am trying to understand the 1-to-many relationships in datastore; but I fail to understand how query and update the record of a user when the model includes ReferenceProperty. Say I have this model:
class User(db.Model):
userEmail = db.StringProperty()
userScore = db.IntegerProperty(default=0)
class Comment(db.Model):
user = db.ReferenceProperty(User, collection_name="comments")
comment = db.StringProperty()
class Venue(db.Model):
user = db.ReferenceProperty(User, collection_name="venues")
venue = db.StringProperty()
If I understand correctly, the same user, uniquely identified by userEmail can have many comments and may be associated with many venues (restaurants etc.)
Now, let's say the user az#example.com is already in the database and he submits a new entry.
Based on this answer I do something like:
q = User.all()
q.filter("userEmail =", az#example.com)
results = q.fetch(1)
newEntry = results[0]
But I am not clear what this does! What I want to do is to update comment and venue fields which are under class Comment and class Venue.
Can you help me understand how this works? Thanks.
The snippet you posted is doing this (see comments):
q = User.all() # prepare User table for querying
q.filter("userEmail =", "az#example.com") # apply filter, email lookup
- this is a simple where clause
results = q.fetch(1) # execute the query, apply limit 1
the_user = results[0] # the results is a list of objects, grab the first one
After this code the_user will be an object that corresponds to the user record with email "az#example.com". Seing you've set up your reference properties, you can access its comments and venues with the_user.comments and the_user.venues. Some venue of these can be modified, say like this:
some_venue = the_user.venues[0] # the first from the list
some_venue.venue = 'At DC. square'
db.put(some_venue) # the entry will be updated
I suggest that you make a general sweep of the gae documentation that has very good examples, you will find it very helpful:
http://code.google.com/appengine/docs/python/overview.html
** UPDATE **: For adding new venue to user, simply create new venue and assign the queried user object as the venue's user attribute:
new_venue = Venue(venue='Jeferson memorial', user=the_user) # careful with the quoting
db.put(new_venue)
To get all Comments for a given user, filter the user property using the key of the user:
comments = Comment.all().filter("user =", user.key()).fetch(50)
So you could first lookup the user by the email, and then search comments or venues using its key.

Categories

Resources