I asked a similar question today (Django: exclude User list from all Users ), the sollution was to write a symmetrical query. Since I changed my models with a many-to-many relation, this solution isn't valid anymore.
How can I exclude a list of users from user instances? With this method:
class Shift(models.Model):
shift_location = models.CharField(max_length=200)
users = models.ManyToManyField(User)
def get_shift_users(self):
return self.users.all()
def get_other_users(self):
return User.objects.all().exclude(self.users.all())
I get the error: AttributeError: 'User' object has no attribute 'split'
You need to use the in operator:
User.objects.exclude(id__in=self.users.all())
By using an unevaluated queryset (self.users.all()), it is transformed in a subquery, so the result will be fetched in a single query.
Maybe something like this:
User.objects.all().exclude(id__in=[u.id for u in self.users.all()])
Related
I have a simple Django ForeignKey relationship between two models in postgreSQL. The logic here is the Sample object can optionally have a foreign key into a type of sample control.
from django.contrib.postgres.fields import CICharField
from django.db import models
class Sample(models.Model):
controls_applied = models.ForeignKey(SampleControl, null=True,
blank=True,
on_delete=models.SET_NULL)
class SampleControl(models.Model):
id = CICharField(max_length=200, primary_key=True)
On the admin changelist for Sample, I am trying to create filter that queries all or none of Samples that have a specific control (in this case, we'll use a SampleControl with id='runcontrol'). I'm trying to craft the specific URI string to append to my changelist url as I have other filters I'm trying to run in conjunction.
To get all samples with controls_applied= 'runcontrol', I can simply append the following string to my URL (notice the reference to the id of the foreign key):
?controls_applied__id=runcontrol
But if I want to get all samples that are not run control, it's more complicated. Wasn't sure what to do, so I decided to use 'startswith', which has a convenient 'notstartswith' companion that will do the inverse. When I use this, I see that the following works:
?controls_applied__id__startswith=runcontrol
However, the inverse
?controls_applied__id__notstartswith=runcontrol
gives me an error: Unsupported lookup 'notstartswith' for CICharField or join on the field not permitted, perhaps you meant startswith or istartswith?
Which leads to me the simple question: is there a way to specify NOT EQUALS in the query string of the URL on Django's admin site? Thank you!
I don't think admin URLs are capable of representing an exclude queryset filter, unless you create your own SimpleListFilter.
Try this in your admin.py:
class WithoutControlListFilter(admin.SimpleListFilter):
title = ('Without Control')
parameter_name = 'without_control'
def lookups(self, request, model_admin):
return (
('runcontrol', ('Run Control')),
)
def queryset(self, request, queryset):
return queryset.exclude(controls_applied=self.value())
class SampleAdmin(admin.ModelAdmin):
list_filter = (WithoutControlListFilter,)
There is a bit of info about admin filters in the Django ModelAdmin docs.
I am trying to print the filtered results from a django model. This is my code
record = StudentInfo.objects.filter(Name=name,
School=school,
City=city,
Country=country)
I know there are 4 entries that satisfy the filter. I now want to print the records. But when I try
print(record)
I get the following
[<StudentInfo: StudentInfo object (1)>, <StudentInfo: StudentInfo object (4)>, <StudentInfo: StudentInfo object (6)>, <StudentInfo: StudentInfo object (8)>]
How do I print the entire record as a list?
What you see in your model instance StudentInfo object (1) is the representation of your model instance. You can change it by overriding the str method on your model.
class StudentInfo(models.Model):
# fields
def __str__(self):
return self.Name
And it'll look like this.
[<StudentInfo: StudentName>, ..]
It's not a good approach to add all fields of your model to your str method.
If you want to see more info on the model instance, create another method on your model and use that.
class StudentInfo(models.Model):
# fields
def __str__(self):
return self.Name
def detail(self):
return f"Name: {self.name}, School: {self.school} ..."
Print your students like this.
for student in record:
print(student.detail())
Also, it's best practice to use all lowercase characters on your model fields. You may want to follow PEP-8 rules for more info.
As I understand you question, a student can have multiple records. So it is better to use SerializerMethodField.
On your student serializer, you can do something like
(considering you have serializer for StudentInfo)
class StudentSerializer(serializer.ModelSerializer):
record = serializer.SerializerMethodField()
class Meta:
model = Student
fields = "__all__"
def get_record(self, obj):
record = StudentInfo.objects.filter(Name=name,
School=school,
City=city,
Country=country)
return StudentInfoSerializer(record, many=True).data
after this, every time you use StudentSerializer, you will get the related record as a list.
when you use filter() method in django it returns all results that satisfies the criteria. The result returned by filter() is called Queryset.
[<StudentInfo: StudentInfo object (1)>, <StudentInfo: StudentInfo object (4)>, <StudentInfo: StudentInfo object (6)>, <StudentInfo: StudentInfo object (8)>]
This is a queryset.
Queryset is a list of objects.
To print the results:
for item in record:
print(item.Name)
print(item.Country)
print(item.School)
print(item.City)
for one iteration of the loop one object from the queryset is taken and we are accessing its properties using dot(.)
All the answers here require adding code to models, creating serializers, in case someone just needs to debug and see list of objects returned, I did it this way:
import json
from django.core.serializers.json import DjangoJSONEncoder
print(json.dumps(list(StudentInfo.objects.filter(Name=name, School=school, City=city, Country=country).values()), cls=DjangoJSONEncoder))
Yeah, Django doesn't make it easy, compared to Laravel, where it's just dd(StudentInfo.where(['Name' => name, 'School' => school, 'City' => city, 'Country' => country])); with a beautiful colored output.
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])
I have a list a on the code, and i want to eliminate duplicated entries.
I saw a very clean method here: http://love-python.blogspot.pt/2008/09/remove-duplicate-items-from-list-using.html
i am using mysql
But when i acesss the page i get this error: 'list' object has no attribute 'all' i can't figure where this is coming from!
forms.py:
from testApp.models import Ficha_medico
from django.forms import ModelForm
from django import forms
class MenuForm(ModelForm):
a = Ficha_medico.objects.values_list('zona', flat=True)
a = list (set(a))
zona = forms.ModelChoiceField(queryset=a)
class Meta:
model = Ficha_medico
Any help appreciated
The error message tells you where it is coming from.
A list is not a queryset. You can't pass it as the queryset parameter of a field.
To eliminate duplicates in a queryset, use .distinct().
.values_list() returns a list object, not a queryset.
Apparently, something like this would work if you're using PostgreSQL:
a = Ficha_medico.objects.distinct('zona')
For others, I suspect there's a better way, but this would work:
class MenuForm(ModelForm):
items = Ficha_medico.objects.values_list(('id', 'zona'), flat=True)
# get a single 'id' per 'zona'
# --> since we don't know how many there are cycle through all
# --> note: this will overwrite existing values, but doesn't seem to matter.
uniques = {z: i for i, z in items}
# re-query to retrieve only the necessary number of unique zona values
qs = Ficha_medico.objects.filter(id__in=uniques.values())
zona = forms.ModelChoiceField(queryset=qs)
class Meta:
model = Ficha_medico
In the models there is a many to many fields as,
from emp.models import Name
def info(request):
name = models.ManyToManyField(Name)
And in emp.models the schema is as
class Name(models.Model):
name = models.CharField(max_length=512)
def __unicode__(self):
return self.name
Now when i want to query a particular id say for ex:
info= info.objects.filter(id=a)
for i in info:
logging.debug(i.name) //gives an error
how should the query be to get the name
Thanks..
info.name is ManyToManyField so if you want all Name objects associated with it you have to use .all() method on it. Only then you'll get list (queryset) of Name objects:
info_list = info.objects.filter(id=a)
for info_object in info_list:
for name_object in info_object.name.all():
print name_object.name
Lukasz is right, but just so you know, it doesn't make sense to filter on an id unless you use info.object.filet(id__in=a) and a is a list of some sort. If you filter on a single id, you should be using objects.get(**kwargs) first of all, and it will return that specific Info instance instead of a QuerySet.