Django add custom permission - python

I am facing the problem of adding custom permission in Django. My idea is that when authorizing a user, if it belongs to group1, only the rows of group1 are displayed, and otherwise the rows of group2. There is a group field in the database table, it contains only two values group1 and group2. In the admin panel, I created 2 groups, respectively, and also included users in these groups. Also I created permissions and assigned them to each user.
My models.py
class Employee(models.Model):
DEPT =(
('Group1', 'Group1'),
('Group2', 'Group2')
)
dept = models.CharField(max_length=100, choices=DEPT, default='')
fio = models.CharField(max_length = 100)
work_place = models.CharField(max_length = 150, default= '')
def __str__(self):
return self.fio
class Meta:
permissions = (
("view_museum", "can view museum"),
("view_ssoismi", "can view ssoismi"),
)
My views.py
def employee_list(request):
context = {'employee_list': Employee.objects.all()}
return render(request, "employee_register/employee_list.html", context)
If i change the context row to
context = {'employee_list': Employee.objects.filter(dept="Group1")}
I get the desired result, but how can do it automatically with django groups and etc.
Maybe i do something wrong?
Any idea what to do next?
Thanks

In the admin panel, I created 2 groups, respectively, and also included users in these groups.
Query these group names by filtering request.user.groups with name__in. Then filter Employee.objects by those results with dept__in.
Note that this assumes the admin group names are named exactly like the Employee.dept field. If not, rename the admin groups to match the Employee.dept field (including capitalization, spaces, etc.).
def employee_list(request):
groups = [g.name for g in request.user.groups.filter(name__in=['Group1', 'Group2')]
context = {'employee_list': Employee.objects.filter(dept__in=groups)}
return render(request, 'employee_register/employee_list.html', context)

Try this:
context = {'employee_list': Employee.objects.filter(dept=request.user.group)}
I'm not sure how you made the User belong in one of the groups but I'm guessing you also have a group field on your User model.

Related

How to use django-filter package for foreign key fields in Django?

Hi all!
New in Django, and confused, help is appreciated! I've created a table, , thanks to a stackoverflow users, like:
Organization
Total amount of appeals
Amount of written form appeals
Amount of oral form appeals
Organization 1
3
1
2
Organization 2
2
1
1
Have three models:
class Organization(models.Model):
organization_name = models.CharField(max_length=50)
class AppealForm(models.Model):
form_name = models.CharField(max_length=50)
class Appeal(models.Model):
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
appeal_form = models.ForeignKey(AppealForm, on_delete=models.CASCADE)
applicant_name = models.CharField(max_length=150)
appeal_date = models.DateField()
Objects of Organization model:
organization_name
Organization 1
Organization 2
Objects of AppealForm model:
form_name
In written form
In oral form
Objects of Appeal model:
organization
appeal_form
applicant_name
Organization 1
In written form
First and Last name
Organization 1
In oral form
First and Last name
Organization 1
In oral form
First and Last name
Organization 2
In written form
First and Last name
Organization 2
In oral form
First and Last name
In the function of views.py file, I've created a query to render, like:
from django.db.models import Count, Q
organizations = Organization.objects.annotate(
).annotate(
total=Count('appeal'),
total_written=Count('appeal', filter=Q(appeal__appeal_form__form_name='in written form')),
total_oral=Count('appeal', filter=Q('appeal__appeal_form__form_name='in oral form'))
)
And now I want to filter table contents by AppealForm model and date of appeals (appeal_date field of Appeal model). Case: User opens a table and from search bar above the table chooses which appeal form and/or the range of dates to see.
Question: How to filter the query which is above in views.py using django-filter package?
The most general way to define a complicated filter is to use the method argument. I can't say I completely understand your problem, but you can apply any filter for which you can dream up a queryset in this way. In outline:
import django-filters as DF
class SomeFilters( DF.FilterSet):
name = DF.xxxFilter( method='my_method', field_name='object_field', label='whatever', ...)
...
def my_method( self, qs, name, value):
# in here you create a new more restrictive queryset based on qs
# to implement your filter, and return it.
# name is the field name. Note, you don't have to use or follow it
# value is the value that the user typed
qs = qs.filter( ...) # or .exclude, or complicated stuff
return qs
Here's a fairly simple method that I wrote to create an annotation with the value of a field stripped of spaces, and then to do a text-contains filter on that.
def filter_array_desc( self, qs, name, value):
value = value.replace(' ','')
qs = qs.annotate(
arr_d_nospaces = Replace( 'array_desc', Value(' '), Value('')) # delete all spaces
).filter(
arr_d_nospaces__icontains = value )
return qs
Here's a general one that can be applied to any field through a ChoiceFilter to filter whether the field is blank or not:
YESNO = (('Y','Yes'), ('N','No'))
marr_b = FD.ChoiceFilter( field_name='marr', label='M_array is blank', method='filter_blank_yesno',
choices=YESNO, empty_label="Don't Care" )
...
def filter_blank_yesno( self, qs, name, value):
if value=="Y":
return qs.filter(**{ name:'' })
elif value=="N":
return qs.exclude( **{ name:'' })
raise ValueError(f'filter_blank_yesno received value="{value}" which is neither "Y" nor "N"')
Hope this helps. You will basically be filtering by following relationships between your models, using double-underscores to move between models, and possibly annotating and filtering on the anotation, or doing things with Q objects and suchlike.

Best way to add/alter fields in a form

I have the following model
class customer_prices(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE,null=True)
price = models.FloatField()
image = models.FloatField()
function = models.TexField()
.
.
(10 more fields)
The fields shown in the homepage is only price thus the other fields are assigned manually, based on the values in a dataframe returned by a self-written some_util_function() e.g
#login_required
def add_price(request):
cleaned_data = form.cleaned_data
df = some_util_function(cleaned_data["price"])
form.user_id = user.id
form.image= df["image"]
.
.
form.save()
messages.success(request, "Price added")
return redirect("my_html")
return render(...)
As we can see each form-field is updated by form.field=df["field"] thus I wonder, if there is another (better way) of doing that?
I have thought about the two following ways:
Instead of form.field=value then form.cleaned_data["field"] = value
Since I have all the data in a dataframe, simply push that dataframe to the given DB e.g df.to_sql("my_table_name").
I know (2) is working, but I think it's better to keep the database changes to Django, and not some mix between pushing data self and let Django handle it.

how to populate user specific data in django

I have 2 models employee and leave, where Employee is the foreign key in Leave. I want to display the leave requests by a specific employee on a page when they log in.
i'm not able to get the leave data populated on, and if there are more than 2 leaves applied by a single employee i get an error saying 2 items found
here is my code
models.py
class Employee(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE)
no_of_leaves=models.IntegerField(
null=False,
validators=[
MinValueValidator(1),
MaxValueValidator(24)
],
default=24
)
def __str__(self):
return self.user.username
class Leave(models.Model):
employee=models.ForeignKey(Employee,on_delete=models.CASCADE,default="")
start_date=models.DateField(auto_now_add=False)
end_date=models.DateField(auto_now_add=False)
req_date=models.DateTimeField(default=datetime.datetime.now())
STATUS_OPTIONS = (
("Approve","Approve"),
("Pending","Pending"),
("Decline","Decline"),
)
approved=models.CharField(max_length=10,choices=STATUS_OPTIONS,default='Pending')
def __str__(self):
return self.employee.user.username
#property
def date_diff(self):
return (self.start_date - self.end_date).days
views.py
def home(request):
user = request.user
u = User.objects.get(username=user)
e = Employee.objects.get(user=user.id)
leave = Leave.objects.get_or_create(employee=e)
print(leave)
nofleaves=None
if user.is_superuser:
pass
else:
nofleaves=u.employee.no_of_leaves
context={'nofleaves':nofleaves,'leave':leave,}
return render(request,"leaveApp/home.html",context)
Just like #Jao said get is to fetch only one data while there is a many to one relationship between Leave and Employee that means there can be multiple Leave for one employee thus get will throw an error.
You should use filter:
Change this line
leave = Leave.objects.get_or_create(employee=e) to something like
leave = Leave.objects.filter(employee=e.id)
if not leave.exists():
leave = Leave.objects.create(employee=e)
This other question might help.
The thing is you should use get for only one data. You shouldn't use get on a many-to-one relathionship. The logic is, there can be multiple Leave by Employee so you can't have a consistent use of get.
What you can use is filter but I'd use related names/related fields which will allow you to use employee.leaves if you define it correctly.

django list_filter filter by id display by name

Currently in the admin interface it is possible to filter the projects by company name not the company instance in the database. Because of that it is impossible to filter out the projects of one specific company if there are multiple companies with the same name.
Please fix it - make it possible to filter projects by actual companies in the database (company name should still be visible in the filter options.
list_filter = ('company__name',)
#I change and become
list_filter = ('company__id',)
But now, the filter displays the id, but name need. How do I display by name but filter by id?
You can define a custom filter class. Something like that might work for you:
class CompanyListFilter(admin.SimpleListFilter):
title = _('company')
parameter_name = 'company_id'
def lookups(self, request, model_admin):
# generate the list of choices
companies = Company.objects.all()
return [(company.pk, company.name) for company in companies]
def queryset(self, request, queryset):
# filter the queryset by the selected value
value = self.value()
if value is not None:
return queryset.filter(company_id=self.value())
return queryset
class ProjectAdmin(admin.ModelAdmin):
# add the filter to the admin instance
list_filter = (CompanyListFilter,)

How to write a complex Mysql Query in Django

I am new to Django and I am working on a small module of a Django application where I need to display the list of people who have common interest as that of any particular User. So Suppose if I am an user I can see the list of people who have similar interests like me.
For this I have 2 models :
models.py
class Entity(models.Model):
name = models.CharField(max_length=255, unique=True)
def __str__(self):
return self.name
class UserLikes(models.Model):
class Meta:
unique_together = (('user', 'entity'),)
user = models.ForeignKey(User)
entity = models.ForeignKey(Entity)
def __str__(self):
return self.user.username + " : " + self.entity.name
So in the Entity Table I store the Entities in which user can be interested Eg : football, Music, Code etc.
and in the UserLikes I store the relation about which user likes which entity.
Now I have a Query to fetch details about which user has maximum interest like any particular user :
SELECT y.user_id, GROUP_CONCAT(y.entity_id) likes, COUNT(*) total
FROM likes_userlikes x
JOIN likes_userlikes y ON y.entity_id = x.entity_id AND y.user_id <> x.user_id
WHERE x.user_id = ?
GROUP BY y.user_id
ORDER BY total desc;
Problem is how do I write this Query using Django Querysets and change it into a function.
# this gives you what are current user's interests
current_user_likes = UserLikes.objects.filter(user__id=user_id) \
.values_list('entity', flat=True).distinct()
# this gives you who are the persons that shares the same interests
user_similar_interests = UserLikes.objects.filter(entity__id__in=current_user_likes) \
.exclude(user__id=user_id) \
.values('user', 'entity').distinct()
# finally the count
user_similar_interests_count = user_similar_interests.count()
Here the user_id is the user's id you want to query for.
One advice though, it's not good practice to use plural form for model names, just use UserLike or better, UserInterest for it. Django would add plural form when it needs to.

Categories