I'm using haystack with whoosh, trying to restrict search results to entries created by the currently logged in user only.
The category model, for which I created an index, has a foreign key:
user = models.ForeignKey(User, editable=False)
And in my custom search view I want to filter like this:
searchqueryset = SearchQuerySet().filter(user=request.user.id)
form = SearchForm(request.GET, searchqueryset=searchqueryset, load_all=True)
if form.is_valid():
query = form.cleaned_data['q']
results = form.search()
In the database there is one entry for table category:
id name user_id
1 test10 1
And the current user id is indeed 1.
But I get No results.
When I do this:
searchqueryset = None
I get the "test10" category entry.
So does anyone know why the user id filter isn't working as expected?
Are you sure that the "user" in your Haystack index holds the integer value of user id? Perhaps it has some other user data(such as username) there, so the comparison simply does not work?
By default the Django user object returns the user name, not the user id.
Related
what does these lines of code mean in Django View: i couldn't find a details explanation, I came to Django from a Laravel background, so I can understand the models and relationships... thanks
customer = request.user.customer
product = Product.objects.get(id=productId)
order, created = Order.objects.get_or_create(customer=customer, complete=False)
orderItem, created = OrderItem.objects.get_or_create(order=order, product=product)
customer = request.user.customer
The request object has a user, the user is the authenticated user (if no user is authenticated then the AnonymousUser object is returned instead). In this example the User model (i.e. the user table) has a field called customer and we are accessing that field.
product = Product.objects.get(id=productId)
Here we are simply querying the Product table for a specific product with the given productId. Note, Django will raise an error if two records are returned when you use the .get() method (i.e. if two rows in the Product table have the same productId.
order, created = Order.objects.get_or_create(customer=customer, complete=False)
Next we use the get_or_create() method to look up an order based off of the customer (the value of which we extracted above. If an order cannot be found we will create one instead. The value of createdwill be True if a neworder` was created or False if one already existed.
orderItem, created = OrderItem.objects.get_or_create(order=order, product=product)
Just as above we are getting or creating an OrderItem using the order and product fields.
We have a postgres jsonb field in Django that allows users to store arbitrary user data. We wish to allow users to query this field but are unsure about the security implications.
The model
from django.db import models
class Item(models.Model):
user = models.ForeignKey("user", null=False)
meta = JSONField()
Query
def custom_query(operation, value):
qs = Item.objects.filter(user=user)
params = {
"meta__" + operation: value
}
qs = qs.filter(**params)
Usage:
Assuming meta is {"a": 1}.
custom_query(operation="contains", value={"a": 1})
custom_query(operation="a", value=1)
The above should be valid and equivalent queries.
Is this a secure way to perform the query?
I'd suggest adding an allowlist for valid operations and maybe checking the value is suitably simple (only strings, for example), but in the presence of other filters that ensure the rows that can be selected are those the user can see, I don't see a problem with this.
I am implementing a User referral system, which existing users can refer other people to register an account with the link they provided. After the new user registers, the new user will be stored to the field 'referred_who' of the existing user.
I have tried using the following method:
class CustomUser(AbstractBaseUser):
...
referred_who = models.ManyToManyField('self', blank=True, symmetrical=False)
class ReferralAward(View):
def get(self, request, *args, **kwargs):
referral_id = self.request.GET['referral_id']
current_referred = self.request.GET['referred']
// referrer
user = get_user_model().objects.filter(referral_id=referral_id)
// user being referred
referred_user = get_user_model().objects.filter(username=current_referred)
for item in user:
previous_referred = item.referred_who
previous_referred.add(referred_user[0])
user.update(referred_who=previous_referred)
And I got the following error:
Cannot update model field <django.db.models.fields.related.ManyToManyField: referred_who> (only non-relations and foreign keys permitted).
I am not sure if this method even works. I have check the Django Admin backend and I realized the 'Referred who' field actually contains all the users. It seems that it only highlightes the user being referred instead of only showing the referred users.
Also, I tried to access the 'referred_who' field in the back-end and it returns 'None'.
Is there a way to stored the users in the 'referred_who' field so that I can see all of the user being referred and access them in the back-end? For instance:
referral_id = self.request.GET['referral_id']
user = get_user_model().objects.filter(referral_id=referral_id)
print(user[0].referred_who)
Can someone show me a better way to do it? Thanks a lot!
You ask how to create a 1-Many field, but in your models you're trying to create m2m. Just change field to FK.
referred_who = models.ForeignKey('self', blank=True).
In case you need to have multiple fks to the same model, you need to specify related_name as well. You can use name of the field for it. More in docs.
In a model, when a foreign key field is created then Django apparently create another field with the same field name followed by _id.
for example if I have
class Post(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,default=None)
dated = models.DateTimeField(auto_now=True)
...
Then I will have the following fields available:
id,user,user_id,dated
I am not sure why this field (user_id) was added?
Later I wanted to override my queryset in a class view
so I was confused which one to use (user field or user_id field)
:
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
Or
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user=self.request.user.id)
I tried both and both worked just fine
My question is:
1) What is the purpose of creating this additional field ?
2) What is the difference between the original foreign key field (user in my case) and user_id field?
3) Will both fields user and user_id available in the database? what is the point of that?
4) Is the content of user and user_id identical in each record? if so ,then what the purpose of this additional field that was created automatically by django?
Thanks a lot
Django only creates one column in the database for the foreign key.
The difference between the field and the _id attribute it generates is that accessing the field performs a query for the full set of columns from the related table in order to construct the complete related object. If you want the full object, use the field (and probably also use select_related() in the initial query to save you from doing N+1 queries).
On the other hand, if all you need is the DB-level value of the foreign key, which is usually the primary key of the related object (and often that is what you want), the _id attribute shortcut is there for you and already has the data, because that's what was actually in the foreign key column.
In other words, suppose I have models like this:
class ModelA(models.Model):
name = models.TextField()
class ModelB(models.Model):
name = models.TextField()
a_instance = models.ForeignKey(ModelA)
If you query for a ModelB, like ModelB.objects.get(pk=12), you'll get a query like this:
SELECT id, name, a_instance_id
FROM your_app.modelb
WHERE id = 12;
Notice a_instance_id is the name of the column -- it's just a foreign key, all it stores is a pointer to the primary key of a ModelA instance. If you just need that primary key, accessing the a_instance_id attribute has it already without needing to do another query. If you access the a_instance field, though, you get to do another query:
SELECT id, name
FROM your_app.modela
WHERE id = (whatever the value of that foreign key was);
In Django, I have a User model and a Following model:
class User():
uid = models.UUIDField(primary_key=True)
class Following():
follower_uid = models.ForeignKey(USER_MODEL, related_name="followers")
followed_uid = models.ForeignKey(USER_MODEL, related_name="following")
with corresponding database tables for both object types.
When Django loads a User object, I want to also load the number of followers of that user in the same database query, i.e. using a join. What I don't want to do is load the user first and then do a second query to get the number of followers.
Is this possible using the Django object model or do I have to write raw sql?
I also want to load a second-degree count; that is, the number of followers of the followers of the user. As before, I want this count to be loaded in the same database query as the user itself.
Appreciate specific syntax and examples, I have read a ton of Django documentation and nothing seems to answer this. Thanks!
you can do this query:
from django.db.models import Count
>>> user = User.objects.filter(pk=some_id).annotate(num_followers=Count('followers'))
>>> user
[<User: someuser>]
>>> user[0].id
some_id
>>> user[0].num_followers
123