How can I Properly use Django Class Based View UserPassesTestMixin in UpdateView - python

I am working on a Django project where users would have one bank record. And I don't want them to be able to update another one's bank record except their own.
I want to use Django UserPassesTestMixin to perform this restriction but I am getting 403 Forbidden error any time I try to access the UpdateView.
Here is my Models code:
class BankDetails(models.Model):
applicant = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
bank = models.CharField(max_length=30, choices=BANK, blank=True, null=True)
account = models.CharField(max_length=20, blank=True, default=None, null = True)
name = models.CharField(max_length=60, blank=True, null=True)
branch = models.CharField(max_length=60, blank=True, null = True)
date = models.DateTimeField(auto_now_add=True)
Here is Class based views code:
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin, UserPassesTestMixin
class UpdateBank(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
template_name = 'user/edit_bank.html'
model = BankDetails
form_class = ApplicantBankForm
def get_success_url(self):
return reverse_lazy('bank-detail',kwargs={'pk': self.get_object().id})
def test_func(self):
return self.get_object().applicant_id == self.request.user.pk
class BankDetailView(LoginRequiredMixin, DetailView):
template_name = 'user/bank_detail.html'
model = BankDetails
def get_success_url(self):
return reverse_lazy('app-submit', kwargs = {'pk' : self.get_object().id})
my urls.py code:
path('<int:pk>/update/', UpdateBank.as_view(), name = 'edit-bank'),

Related

How to request user login in models or views

I am newbie in Django, and I can’t figure out how to get username through request. I’m working on vocabulary type site and I need that every entry user creates would have username.
Here is my models.py
from django.db import models
class EngDict(models.Model):
orig_word = models.CharField(max_length=500, null=False,blank=False, verbose_name='Слово')
translate = models.CharField(max_length=500,null=False,blank=False, verbose_name="Перевод")
remarks = models.TextField(null=True, blank=True, verbose_name="Примечания")
published_by = models.CharField(max_length=50, verbose_name="Добавлено")
published_date = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name="Дата добавления")
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.PROTECT, verbose_name = 'Категория')
class Meta:
verbose_name = ("Перевод")
verbose_name_plural = "Англо-русский словарь"
ordering = ['-published_date']
This is views.py
from django.shortcuts import render
from django.template import loader
from .models import EngDict, Category
from django.views.generic.edit import CreateView
from .forms import EngDictForm
from django.urls import reverse_lazy
from django.views.generic import TemplateView, ListView, FormView
from django.db.models import Q
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login
class EngDictCreateView(CreateView):
template_name = 'dict/create.html'
form_class = EngDictForm
success_url = reverse_lazy('index')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['categories'] = Category.objects.all()
return context
I see that I need some function like def user_name(request) , but I can’t understand where i should write it and what must be inside of it. I need that published_by variable was automatically filled in with user login
Added exclude in forms.py
from django.forms import ModelForm
from .models import EngDict
from django import forms
class EngDictForm (ModelForm):
def clean_orig_word(self):
data = self.cleaned_data['orig_word']
if EngDict.objects.filter(orig_word = data).count():
raise forms.ValidationError("ТАКОЕ СЛОВО УЖЕ ЕСТЬ!")
return data
class Meta:
model = EngDict
fields = ('orig_word', 'translate', 'remarks', 'published_by')
exclude =['published_by']
Please do not use a CharField for that. If later the user changes their username, then it refers to a user that no longer exists. To refer to another object, one uses a relation field like a ForeignKey [Django-doc], OneToOneField [Django-doc], or , ManyToManyField [Django-doc]. Here it looks like a ForeignKey is what you are looking for:
from django.conf import settings
class EngDict(models.Model):
orig_word = models.CharField(max_length=500, null=False,blank=False, verbose_name='Слово')
translate = models.CharField(max_length=500,null=False,blank=False, verbose_name='Перевод')
remarks = models.TextField(null=True, blank=True, verbose_name='Примечания')
published_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
editable=False,
verbose_name='Добавлено'
)
published_date = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата добавления')
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.PROTECT, verbose_name = 'Категория')
class Meta:
verbose_name = ('Перевод')
verbose_name_plural = 'Англо-русский словарь'
ordering = ['-published_date']
In the form you should exclude published_by and in the CreateView, you can then "patch" the object with:
from django.contrib.auth.mixins import LoginRequiredMixin
class EngDictCreateView(LoginRequiredMixin, CreateView):
template_name = 'dict/create.html'
form_class = EngDictForm
success_url = reverse_lazy('index')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['categories'] = Category.objects.all()
return context
def form_valid(self, form):
form.instance.published_by = self.request.user
return super().form_valid(form)
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin mixin [Django-doc].

how to check and pass the instance of the user in my form in Django?

Hi I'm trying to create a form that accepts Log from the user however I don't know how to pass the instance of the user. I'm used to creating a CreateView for this, however since I'm planning to use customized widgets and settings, I'm using a modelform to create logs for the user.
My question is is this the same way as create view to check the instance of the user?
Is it still the same as what I did to my createview which is:
def form_valid(self,form) :
form.instance.testuser = self.request.user
return super().form_valid(form)
Or do I have to do something else entirely?
Here is my Forms.py:
from django import forms
from profiles.models import User
from .models import DPRLog
class DateInput (forms.DateInput):
input_type = 'date'
class Datefield (forms.Form):
date_field=forms.DateField(widget=DateInput)
class dprform(forms.ModelForm):
class Meta:
model = DPRLog
widgets = {'reportDate':DateInput()}
fields = ['status','login','logout','reportDate','mainTasks','remarks']
Models.py:
from django.db import models
from profiles.models import User
from django.urls import reverse
# Create your models here.
class Points(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
class Manager(models.Model):
manager = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return self.manager.full_name
class Member(models.Model):
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=30, null=True)
def __str__(self):
return self.member.full_name
class Job(models.Model):
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField(auto_now=True)
file = models.FileField(null=True, blank=True, upload_to='job_files')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('job-detail', kwargs={'pk': self.pk})
class DPRLog(models.Model):
STATUS_CHOICES = (
('PENDING', 'PENDING'),
('CANCELLED', 'CANCELLED'),
('COMPLETED', 'COMPLETED'),
)
TASKS_CHOICES = (
('TESTS EXECUTION', 'TESTS EXECUTION'),
('TESTS DESIGN', 'TESTS DESIGN'),
('MOBILE TESTING WORKSHOP', 'MOBILE TESTING WORKSHOP'),
('BENCH ACTIVITY', 'BENCH ACTIVITY'),
('DEFECT ANALYSIS','DEFECT ANALYSIS'),
)
testuser = models.ForeignKey(User,on_delete = models.CASCADE)
status = models.CharField(max_length=30, choices=STATUS_CHOICES,null=True)
reportDate = models.DateField(blank=False, null=False)
login = models.TimeField(blank=False, null=False)
logout = models.TimeField(blank=False, null=False)
mainTasks = models.CharField(max_length=50, blank=False, choices=TASKS_CHOICES, null=True)
remarks = models.CharField(max_length=30,null=True)
def __str__(self):
return f'{self.testuser.full_name} DPR Log'
Views.py:
def dprmodelform(request):
if request.method=='POST':
form = dprform(request.POST)
if form.is_valid():
form.save()
form = dprform()
return render (request,'users/dprform.html',{'form':form})
def form_valid(self,form) :
form.instance.testuser = self.request.user
return super().form_valid(form)
class dprview(LoginRequiredMixin,ListView):
model = DPRLog
template_name = 'users/dpr_view.html'
context_object_name = 'log'
If you pass commit=False to form.save() you can get the instance from the validated form without saving to the database. You can then set the user attribute on the instance before calling save again
if form.is_valid():
instance = form.save(commit=False)
instance.testuser = request.user
instance.save()

Check if user is in the manager column in order to create a post/task

I'm learning in DJango and I have learned alot of stuff from the documentation and also in StackOverflow. Right now, I'm kinda stuck and I just want to know who can I check in a class based view, if the user is in the manager column in job model/ It can also be in the manager model that's fine too.
I tried using UserPassesTestMixinin order to check if user is part of it but I'm getting an error of Generic detail view createjob must be called with either an object pk or a slug in the URLconf.
I just need someone to point me to the right direction or give me a hint.I also tried, this:
class createjob (LoginRequiredMixin,CreateView):
model = Job
fields = ['member','title', 'description', 'file']
def form_valid(self,form):
form.instance.manager=self.request.user
return super().form_valid(form)
But it's giving me an error of Cannot assign "<SimpleLazyObject: <User: edlabra>>": "Job.manager" must be a "Manager" instance.
Here's my views.py:
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import ListView, CreateView
from .models import Job, Member
from profiles.models import User
from django.contrib.auth.decorators import login_required
# Create your views here.
class jobs(LoginRequiredMixin,ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
def get_queryset(self):
return Job.objects.filter(member__member=self.request.user)
class createdjobs(LoginRequiredMixin,ListView):
model = Job
template_name = 'users/manager_jobs.html'
context_object_name = 'jobs'
def get_queryset(self):
return Job.objects.filter(manager__manager=self.request.user)
class teamview(LoginRequiredMixin,ListView):
model = Member
template_name = 'users/manage_team.html'
context_object_name = 'members'
def get_queryset(self):
return Member.objects.filter(manager__manager=self.request.user)
class createjob (LoginRequiredMixin,UserPassesTestMixin,CreateView):
model = Job
fields = ['member','title', 'description', 'file']
def test_func(self):
job=self.get_object()
if self.request.user == Job.manager:
return True
return False
Models.py:
from django.db import models
from profiles.models import User
# Create your models here.
class Points (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}Profile'
class Manager (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Member (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Job (models.Model):
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField (auto_now = True)
file = models.FileField(null=True, blank=True,upload_to='job_files')
def __str__(self):
return self.title
assign user from manager table.
def form_valid(self,form):
form.instance.manager=Manager.objects.get(manager=self.request.user)
return super().form_valid(form)

How can I check whether a person is included in a model to make a Job/Post

I have created a School System-like system, that creates a job and sends them to employees/users. I'm almost done making this system however I can't seem to know what do to check if the user is included in the manager model that I created to create a job.
Also, how can a user just see all their job that was assigned to them. All I know is to use objects.allbut that might only seem to show all of the jobs that was posted, I just want the user to see the job included to them.
Here is my model.py:
from django.db import models
from profiles.models import User
# Create your models here.
class Points (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile (models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}Profile'
class Manager (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Member (models.Model):
name = models.CharField(max_length=30, blank=True, null=True)
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Job (models.Model):
manager = models.OneToOneField(Manager, on_delete=models.CASCADE)
member = models.OneToOneField(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField (auto_now = True)
file = models.FileField(null=True, blank=True,upload_to='job_files')
def __str__(self):
return self.title
And Views.py:
from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import Job
from profiles.models import User
# Create your views here.
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
class createjob (CreateView):
model = Job
fields = ['member','title', 'description', 'file']
How can I proceed?
Use get_queryset to filter job by user
Ex:
class jobs(ListView):
model = Job
template_name = 'users/user_jobs.html'
context_object_name = 'jobs'
def get_queryset(self):
return Job.objects.filter(member__member=self.request.user)

Implementing product upload dynamically using Django 1.6

So I am using my admin interface to add product information for different items that will be on my site. I am looking to add the product information from my models to a template view, but I would like for every time I add a new product using my admin interface, for the template to generate a new Li tag with the current product information and picture used of the entered data within the admin interface.
I have not yet implemented any template logic in my views.py yet I am stumped on how to really wrap my head around making this whole process happen. So can anyone help guide me on how to implement this solution?
Thank You!
Here is my code below:
Models.py
from __future__ import unicode_literals
from django.db import models
from django.utils.translation import ugettext_lazy as _
import datetime
class Designer(models.Model):
name = models.CharField(max_length=254, blank=True, null=True)
label_name = models.CharField(max_length=254, blank=True, null=True)
description = models.TextField(null=True, blank=True)
specialites = models.CharField(max_length=254, null=True, blank=True)
image = models.ImageField(upload_to='images/designers/main',max_length=100, null=True) #For the argument upload_to, will add to the static folder and generated image will be stored in suing that path specified
#For Admin Purposes, to track and see which if still active by for administrative users only
is_active = models.BooleanField(default=True)
#Metadata
class Meta:
verbose_name = _("Designer Information")
verbose_name_plural = _("Designers")
#Helps return something meaningful, to show within the admin interface for easy interaction
def __unicode__(self):
return "{0} {1}".format(self.name, self.label_name)
class Boutique(models.Model):
name = models.CharField(max_length=254, blank=True, null=True)
address = models.CharField(max_length=255, blank=True, null=True)
city = models.CharField(max_length=50, null=True, blank=True)
state = models.CharField(max_length=2, null=True, blank=True)
zipcode = models.IntegerField(max_length=5, null=True, blank=True)
boutique_website = models.URLField(max_length=200, null=True, blank=True)
#For Admin Purposes, to track a product to see which is active by administrative users
is_active = models.BooleanField(default=True)
#Foreign Keys & other relationships
designer = models.ForeignKey(Designer)
#Metadata
class Meta:
verbose_name = _("Boutique Information")
verbose_name_plural = _("Boutiques")
#Helps return something meaningful, to show within the admin interface for easy interaction
def __unicode__(self):
return "{0}, {1}, {2}".format(self.name, self.city, self.state)
class ProductCategory(models.Model):
name = models.CharField(max_length=255L, blank=True, null=True)
slug = models.SlugField(max_length=50, unique=True, help_text='Unique value for product page URL, created from name.')
#For Admin Purposes, to track and see which if still active by for administrative users only
is_active = models.BooleanField(default=True)
#For Admin Purposes, to track when we add each product and each product was updated by administrative users
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
#Metadata
class Meta:
verbose_name = _("Product Category")
verbose_name_plural = _("Product Categories")
#Helps return something meaningful, to show within the admin interface for easy interaction
def __unicode__(self):
return "{0}".format(self.name)
class Product(models.Model):
name = models.CharField(max_length=254, blank=True, null=True)
description = models.TextField(blank=True, null=True)
color_name = models.CharField(max_length=254, null=True, blank=True)
size_types = models.CharField(max_length=7, null=True, blank=True)
product_price = models.DecimalField(max_digits=9,decimal_places=2)
old_price = models.DecimalField(max_digits=9,decimal_places=2, blank=True,default=0.00) #To show original price if, new price has been added
product_tags = models.CharField(max_length=254, null=True, blank=True, help_text='Comma-delimited set of SEO keywords for product tag area')
novelty = models.CharField(max_length=254, null=True, blank=True)
product_website = models.URLField(max_length=200, null=True, blank=True) #To show other sites to Users, where they can purchase the particular product
image = models.ImageField(upload_to='images/products/main',max_length=100, null=True) #For the argument upload_to, will add to the static folder and generated image will be stored in suing that path specified
slug = models.SlugField(max_length=255, unique=True, help_text='Unique value for product page URL, created from name.')
#This shows when each item was uploaded & by who, to the User
uploaded_by = models.CharField(max_length=254, blank=True, null=True)
uploaded_at = models.DateTimeField(auto_now=True)
#For Admin Purposes, to track and see which if still active by for administrative users only
is_active = models.BooleanField(default=True)
#Foreign Keys & other relationships
designer = models.ForeignKey(Designer)
boutique = models.ForeignKey(Boutique)
category = models.ForeignKey(ProductCategory)
#Metadata
class Meta:
verbose_name = _("Product")
verbose_name_plural = _("Products")
#Helps return something meaningful, to show within the admin interface for easy interaction
def __unicode__(self):
return "{0}".format(self.name)
Admin.py
from __future__ import unicode_literals
from django.contrib import admin
from products.models import Designer, Product, ProductCategory, Boutique
class DesignerAdmin(admin.ModelAdmin):
list_display = ["name", "label_name", "description", "specialites", "image", "is_active"]
search_fields = ["name", "label_name"]
list_per_page = 50
class ProductAdmin(admin.ModelAdmin):
list_display = ["name", "description", "color_name", "size_types", "product_price", "old_price", "product_tags", "novelty","product_website", "image", "slug", "uploaded_by", "uploaded_at", "is_active"]
search_fields = ["name", "product_price"]
list_per_page = 25
class ProductCategoryAdmin(admin.ModelAdmin):
list_display = ["name", "slug", "is_active", "created_at", "updated_at"]
search_fields = ["name"]
list_per_page = 25
class BoutiqueAdmin(admin.ModelAdmin):
list_display = ["name", "address", "city", "state", "zipcode", "boutique_website", "is_active"]
search_fields = ["name"]
list_per_page = 10
#Register Models below
admin.site.register(Boutique, BoutiqueAdmin)
admin.site.register(Designer, DesignerAdmin)
admin.site.register(Product, ProductAdmin)
admin.site.register(ProductCategory, ProductCategoryAdmin)
Forms.py
from __future__ import unicode_literals
from django import forms
from django.forms import extras, ModelForm
from products.models import Designer, Product, ProductCategory, Boutique
class DesignerForm(ModelForm):
class Meta:
model = Designer
class ProductForm(ModelForm):
class Meta:
model = Product
class BoutiqueForm(ModelForm):
class Meta:
model = Boutique
class ProductCategoryForm(ModelForm):
class Meta:
model = ProductCategory
Views.Py
from __future__ import unicode_literals
from django.http import Http404, HttpResponseForbidden
from django.shortcuts import redirect, get_object_or_404
from django.utils.http import base36_to_int, int_to_base36
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateResponseMixin, View
from django.views.generic.edit import FormView
from django.contrib import auth, messages
from django.contrib.sites.models import get_current_site
from django.shortcuts import render
from products.forms import ProductForm, ProductCategoryForm
from products.forms import BoutiqueForm
from products.forms import DesignerForm
from products.models import Boutique, Product, ProductCategory, Designer
class ProductView(FormView):
template_name = "product_detail/product.html"
form_class = ProductForm
template_var={}
def __init__(self, *arg):
super(ProductView, self).__init__()
self.arg = arg
class ProductCategoryView(FormView):
form_class = ProductCategoryForm
template_var={}
def __init__(self, *arg):
super(ProductCategory, self).__init__()
self.arg = arg
The easiest way to do this is a simple ListView from Django's generic class-based views.
First, string up your views.py:
from django.views.generic import ListView
class ProductListView(ListView):
model = Product
template_name = 'product/list_view.html' # Edit this to whatever your template is.
Remember to edit your urls.py:
from .views import ProductListView
urlpatterns = patterns('',
...
url(r'^product/$', ProductListView.as_view(), name='list'), # Edit url path and name as desired
...
)
Then, make your template:
<div class="jumbotron">
<ul>
{% for product in products %}
<li>{{ product.name }}: {{ product.description }} <img src="{{ product.image.url }}" >
{% endfor %}
</ul>
</div>
This is a very basic template which you'll obviously want to customize. For each Product in your database, it will display the name, description, and the image. You can customize your fields as you desire.
Other potential issues:
1) Be sure you provide the correct path to your template in your ListView.
2) Set up your MEDIA_URL and other media settings to allow your Product image to display.
3) Look at other customization options in ListView (see documentation here.)

Categories