how to create a SimpleListFilter in django - django

I don't succeed to write a query filter.
I have 3 models: Patient, Prescription and User
I write you only what is relevant for my question
Patient:
class Patient(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Prescription:
class Prescription(models.Model):
user = models.ForeignKey(
User,
null=True,
blank=False,
on_delete=models.DO_NOTHING
)
file_extention = models.CharField(
'file extention',
max_length=8,
null=True,
blank=True,
)
So the relation between both of models (Patient and Prescription) are through User.
in the PatientAdmin, I want to filter on the file_extension according pdf or jpg of the prescription uploaded.
I created a SimpleListFilter but impossible to find the right query.
class PrescriptionFileExtensionFilter(SimpleListFilter):
"""This filter is being used in django admin panel in
patient model."""
title = 'Prescription File Ext'
parameter_name = 'file_extention'
def lookups(self, request, model_admin):
return (
('pdf', 'PDF'),
('jpg', 'JPG'),
)
def queryset(self, request, queryset):
for user in queryset:
if self.value() == 'pdf':
return queryset.filter(user=user.user).filter
(prescription__file_extention="pdf")
if self.value() == 'jpg':
return queryset.filter(user=user.user).filter
(prescription__file_extention="jpg")
That's not working...
Do I need the for user in queryset:
need What could be the query to bring me all the users with a prescription with file_extension = "pdf" (or "jpg")

You are trying to get a key from the prescription object in print(mydict['file_extention']) which I believe is causing the issue - you would instead access that property via mydict.file_extention - though I should add that mydict is not an accurate variable name for a model object as it isn't a dictionary. I don't think that for loop is actually doing anything other than printing a particular value so it can be removed altogether.
As an aside, you have two filters on your queryset, this can just be expressed as a single filter, separate by a comma, e.g.
return queryset.filter(user=user.user, prescription__file_extention="pdf")
You are also calling user.user, presumably you just want to get the user model which is kept in request.user - is that what your for loop was trying to do?
Edit
If you want to get all of the users but just filtered by JPG or PDF then you need to remove two things:
The for-loop of for user in queryset
The filter of .filter(user=user.user)
The for loop is unnecessary in the queryset function and the filter is just getting a single user, but you want to get all of them - correct?

Related

how to use delete() query in django?

I am trying to delete one of the items of a field in the table.
For example, I want to remove the 'hadi', shown in the image, from the table.
I make query to filter and exclude instance but in final part, delete() query does not accept input such as id or variable to remove specific thing in one field.
image
models.py
class Expense(models.Model):
expenser = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
debtors = models.ManyToManyField(
CustomUser,
related_name='debtors',
)
amount = models.PositiveIntegerField()
text = models.TextField()
date = models.DateField(null=True)
time = models.TimeField(null=True)
def get_debtors(self):
return ", ".join([str(d) for d in self.debtors.all()])
def who_has_no_paid(self):
return ", ".join([str(d) for d in self.debtors.all() if str(d) != str(self.expenser)])
def debt(self):
return int(float(self.amount/self.debtors.all().count()))
def get_absolute_url(self):
return reverse('expense_detail', args=[self.id])
Now what is the query that should be used in view?
Since it is a many to many field you need to use expense_obj.debtors.remove(hadi_obj) rather than using delete().
Documentation is really good for referencing
your view could be :
def remove_hadi(request):
expense_obj = Expense.objects.get(id=some_id) #get the expense obj from where u want to remove hadi
hadi_obj = User.objects.get(name="hadi") # get user obj u want to remove eg: hadi
# use m2m query
expense_obj.debtors.remove(hadi_obj)
return response

Django ManyToMany relationship, filter options of modelmultiplechoicefield

I am currently rewriting a web app that is utilizing a hierarchy of relationships which is making it extremely painful to create a reliable work flow for the creation of objects. The current set up is as follows:
Customer Hierarchy:
Organization -> Location -> Room
Contacts can belong to one or many of these entries at any level of the hierarchy. Ex Jim can be assigned to Organization and location.
With this I need to filter the django many to many field that is populated with any contact that doesn't belong anywhere OR belongs to a parent or child level of the customer hierarchy.
I have attempted inline formsets which fails on the many to many model as well as limit_choices_to={'Organization':_get_self_pk} . This works but doesn't allow for the use of django admin style on the fly creation of contacts. I have also attempted to use a queryset in the init function for create, but my form has a nested inline formset that doesn't allow me to use the self.field['contact'] to inject the queryset. (Key Error, contacts doesn't exist as a field)
Models.py
class Organization(AbstractExclusions, AbstractManyToManyCommonInfo, AbstractCommonInfo, AbstractOrganizationLocationCommonInfo, AbstractAcvitivyInfo):
....
contact = models.ManyToManyField('Contact', blank=True)
class Location(AbstractManyToManyCommonInfo, AbstractCommonInfo, AbstractOrganizationLocationCommonInfo, AbstractLocationRoomCommonInfo, AbstractAcvitivyInfo, AbstractExclusions):
....
contact = models.ManyToManyField('Contact', blank=True)
class Room(AbstractManyToManyCommonInfo, AbstractCommonInfo, AbstractLocationRoomCommonInfo, AbstractAcvitivyInfo, AbstractExclusions):
....
contact = models.ManyToManyField('Contact', blank=True)
class Contact(AbstractUserInfo):
phone_number = PhoneNumberField(verbose_name=_('Phone Number'))
is_user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE, verbose_name=_('Link To Authenticated User'),)
role = models.ForeignKey(refModels.Role, verbose_name=_("Role"), on_delete=models.CASCADE, null=True, blank=True)
This question was answered by creating a special init function as shown below:
def __init__(self, *args, **kwargs):
super(OrganizationForm, self).__init__(*args, **kwargs)
if 'initial' in kwargs:
try:
self.fields['contact'].queryset = (custModels.Contact.objects.filter(Q(organization = None) | Q(organization = self.instance.id)))
except:
pass

How to get object using filter on ManyToManyField

Why target_dialogue is always None?
Model:
class Dialogue(models.Model):
name = models.CharField(max_length=30, blank=True)
is_conference = models.BooleanField(default=False)
participants = models.ManyToManyField(
Person,
related_name='dialogues',
)
def __str__(self):
return self.name or str(self.pk)
And in view I want to get suitable dialogue which contain in participants field 2 objects - user and companion. And if this dialogue doesn't exist I create it:
target_dialogue = None
try:
target_dialogue = Dialogue.objects.get(is_conference=False,participants__in=[user, companion])
except ObjectDoesNotExist:
target_dialogue = Dialogue()
target_dialogue.save()
target_dialogue.participants.add(user)
target_dialogue.participants.add(companion)
finally:
return render(request, 'dialogues/dialogue.html', {
'dialogue': target_dialogue,
})
But target_dialogue is always None. What's a reason of it? I was supposed to solve only a trouble in getting a dialogue from db in order to bad filter parameters, but now I have doubts about it. Maybe something else?
request.user is not a object of Person model with which you have the relation in Dialogue.
You have to first fetch the person object:
user = Person.objecs.get(user=request.user). # According to your person model
Follow same for companion and then query:
target_dialogues = Dialogue.objects.filter(is_conference=False,participants__in=[user,companion]

Save related models in one query

Hi I have two related models, I need to save it depends on json data from Angular.
Here is models:
Class Company(models.Model):
name = models.CharField(
max_length=255, )
class ContactPerson(models.Model):
company = models.ForeignKey(
Company,
related_name='contact_persons', )
name = models.CharField(
max_length=255, )
Here is part of view:
class CompanyCreate(JsonView):
#JsonView write by me, contains some methods
def post(self, *args, **kwargs):
data = json.loads(self.request.body)
company = CompanyForm(data=data['company'])
contacts = ContactForm(data=data['contacts'])
if company.is_valid():
company.save()
if contacts.is_valid():
contacts.save(commit=False)
contacts.company = company
contacts.save()
return HttpResponse()
Company is saving, but I cant valid contacts form, because I cant get company.id from first form.
I don't think you could save them at once because:
They are instances that has foreign key relationships, so one wouldn't exist before the other.
They are 3 different model instances so it doesn't make sense to combine them in one form.
If you just want to save the ones that are valid and reject the ones that are invalid, what you currently do is enough with one change, capturing the return value of save() function:
class CompanyCreate(JsonView):
#JsonView write by me, contains some methods
def post(self, *args, **kwargs):
data = json.loads(self.request.body)
company_form = CompanyForm(data=data['company'])
contacts_form = ContactForm(data=data['contacts'])
if company_form.is_valid():
company = company_form.save()
if contacts.is_valid():
contacts = contacts_form.save(commit=False)
contacts.company = company
contacts.save()
return HttpResponse()
If you want "all or none" logic, meaning you either save everything if everything is valid, otherwise don't save anything, you should exclude the foreign key on each ModelForm, so that when you valid the forms, they ignore the validation of existence of ForeignKey but not all other fields. See if that makes sense.

Create Django Table displaying information about users

I am currently using django 1.8 and I'd like to create a more intelligent way to display information about users. Say I have something like this:
class User(models.Model):
name = models.CharField()
class Invitation(models.Model):
inviter = models.ForeignKey(User)
invitee = models.ForeignKey(User)
I want to create a field that is the unique number of user's an inviter has invited. I could see how this could be done with something like set("SELECT invitee FROM INVITATIONS WHERE inviter = 'my-user';"), but if I want this displayed in the admin panel, is there a simple way to present this?
Also, I would want this done for every user, so it feels like there is a simple way to make a field generated for every user in the table.
First, let's setup proper related_name- it'll help reduce a lot of confusion in the code.
class Invitation(models.Model):
inviter = models.ForeignKey(User, related_name="invitation_sent")
invitee = models.ForeignKey(User, related_name="invitation_recv")
With the related_name setup, we can do queries such as
user = User.objects.get(pk=1)
# retrieve all invitation objects sent by this user
user.invitation_sent.all()
# retrieve all invitation objects received by this user
user.invitation_recv.all()
Now we can actually count the number of unique invitations a user has sent out quite easily:
# count number of distinct invitee for user
user.invitation_sent.all().values('invitee').distinct().count()
Next, we can actually count the number of unique users a user has invited in a single database query for all users:
user_list = User.objects.all().annotate(
uniq_inv=Count('invitation_sent__invitee', distinct=True)
)
Each user object returned will have an additional property called uniq_inv which contains the count of unique users the user has invited
for user in user_list:
print(user.name + ' invited ' + user.uniq_inv + ' unique users')
To apply this to the admin interface, you'll need to override get_queryset method:
class MyAdmin(admin.ModelAdmin):
...
list_display = [..., 'uniq_inv']
def uniq_inv(self, obj):
return obj.uniq_inv
uniq_inv.short_description = 'Unique Invitees'
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
qs = qs.annotate(uniq_inv=Count('invitation_sent__invitee', distinct=True))
return qs
You can use annotate, which allows to add calculated fields to a queryset.
Models:
class User(models.Model):
name = models.CharField()
class Invitation(models.Model):
inviter = models.ForeignKey(User,related_name="inviter_user")
invitee = models.ForeignKey(User,related_name="invited_user")
Queryset:
from django.db.models import Count
q = Invitation.objects.annotate(count_invitee=Count('invitee')).all()
Now "count_invitee" field has the number for each invitation object.
If you want to filter invitee from the user side.
For a single user:
User.objects.get(pk=1).invited_user.all.count()
For all users queryset:
User.objects.annotate((count_invitee=Count('invited_user')).all()