'QuerySet' object does not support item assignment - python

class PostDetailView(DetailView):
model = Post
template_name = 'detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
instance = Post.objects.get(pk=self.kwargs.get('pk'))
user = instance.post_user
context['comments'] = Comment.objects.filter(comment_post=instance.pk)
context['comments']['profile'] = Profile.objects.get(user=user)
return context
This is my view so far. When i use that code i get this error 'QuerySet' object does not support item assignment. How do i attach the line below correctly?
context['comments']['profile'] = Profile.objects.get(user=user)

The problems is that value of context['comments'] is not a dictionary but QuerySet object.
So you can't do:
context['comments']['profile'] = Profile.objects.get(user=user).
Maybe you can add relation with Profile model right to the Comment model, like:
class Comment(models.Model):
profile = models.ForeignKey(Profile, ...)
...
So then you can have access to the value of Profile who left a comment.

Related

How to initialize foreign key into a form in Django?

I have these two models, one Voucher model is a foreign key to the RegistrationForm model. Anytime someone does a search and the item exists in the Voucher model, I want it to be initialized to the Registration form and saved.
Error Message
raise ValueError(
ValueError: Cannot assign "'phr201'": "RegistrationForm.voucher" must be a "Voucher" instance.
Models
class Voucher(models.Model):
name = models.CharField(max_length=120, null=True, blank=True)
class RegistrationForm(models.Model):
voucher = models.OneToOneField(Voucher, on_delete=models.CASCADE)
full_Name = models.CharField(max_length=200,)
Date_of_birth = models.CharField(max_length=100)
View.py
class RegistrationProcessing(generic.CreateView):
form_class = Registerform
template_name = 'RegistrationProcessing.html'
def form_valid(self, form):
form.instance.voucher = self.request.GET.get('q')
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super(RegistrationProcessing, self).get_context_data(**kwargs)
query = self.request.GET.get('q', default='')
print(query.id)
context.update({
'job_listing': Voucher.objects.filter(
Q(name__iexact=query)
)
})
return context
As error says Cannot assign "'phr201'": "RegistrationForm.voucher" must be a "Voucher" instance
You're trying to assign a string to a OneToOne relation you've to pass a instance of Voucher instead of passing string you've to do like this
def form_valid(self, form):
voucher_instance = Voucher.objects.get(name=self.request.GET.get('q'))
form.instance.voucher = voucher_instance
return super().form_valid(form)
here I'm using get so it will raise an exception if given query does not exists you've to handle it in try except block or you can use other way like this
Voucher.objects.filter(name=self.request.GET.get('q')).first()
or use get_object_or_404()

How to pass PK into a method decorator

Hello guys i am trying to implement some form of access control on my views. My programme is structured as such:
1 project has some users which are tied to it in the form of a foreign key. I only wish to allow those whom are involved in it to view this project. The problem however is that the PK i use to query the database for my template is in my URL , users which do not have access to the project can simply change the url query and gain access to the items they do not have access to.
I came across django's user_passes_test method decorator and thought that it is exactly what i needed to implement this user access control.
Here is some code that i have came up with:
My view:
#method_decorator(user_passes_test(project_check(id)),name ='dispatch')
class ProjectDetailView(CreateView):
##this is actually not relavant##
model = SalesNotation
fields = ['sales_notes']
exclude = ['notation_id']
template_name = 'rnd/projects.html'
context_object_name = 'form'
##this is actually not relavant##
def get_context_data(self, **kwargs):
id = self.kwargs['id']
context = super(ProjectDetailView, self).get_context_data(**kwargs)
context['projects'] = SalesProject.objects.filter(sales_project_id = id)
This is my URL:
path('projects/<int:id>/', ProjectDetailView.as_view(), name = 'rnd-projects'),
This is my project model:
class SalesProject(models.Model):
sales_project_id = models.AutoField(primary_key=True)
sales_project_name = models.CharField(max_length=100)
salesExtra = models.ManyToManyField('SalesExtra', blank=True)
Here is my extended user model which i use to keep other information:
class SalesExtra(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
user_type = models.TextField(max_length=500, choices= role)
contact = models.IntegerField()
email = models.TextField(max_length=30,default = 'your email here')
Here is the method decorator that im using:
def project_check(user,id):
return SalesProject.objects.filter(sales_project_id=id).filter(salesExtra__user=user)
However it seems that i am unable to simply pass in the PK from the url as i recieve this error when running the server:
#method_decorator(user_passes_test(project_check(id) , name='dispatch'))
TypeError: project_check() missing 1 required positional argument: 'id
Any help will be greatly appreciated!
You can't. But you can just use UserPassesTestMixin instead:
from django.contrib.auth.mixins import UserPassesTestMixin
class ProjectDetailView(UserPassesTestMixin, CreateView):
##this is actually not relavant##
model = SalesNotation
fields = ['sales_notes']
exclude = ['notation_id']
template_name = 'rnd/projects.html'
context_object_name = 'form'
##this is actually not relavant##
def get_context_data(self, **kwargs):
id = self.kwargs['id']
context = super(ProjectDetailView, self).get_context_data(**kwargs)
context['projects'] = SalesProject.objects.filter(sales_project_id = id)
def test_func(self):
return SalesProject.objects.filter(sales_project_id=self.kwargs["id"]).filter(salesExtra__user=self.request.user)
Note test_func here which performs check. self.kwargs["id"] will give you id.

Python/Django - not access to linked model in a generic view

I'm newbie in Python and Django
I've 3 models linked: patient -> visit -> prescription
I want to override get_context_data in a detailView to have access to all prescription related to patient
visit to patient related_name = 'visits'
prescription to visit related_name = 'prescriptions'
but I have an error:
PatientFile object has no attribute 'visits'
I look what is inside self:
patient.views.PatientFile object at 0x04772EB0
I don't understand
self is my patient instance so I should have access to all visits with attribute 'visits'?
class PatientFile(DetailView):
model = Patient
context_object_name = "patient"
template_name = "patient/file.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['prescriptions'] = []
print('self : ', self)
for visit in self.visits:
context['prescriptions'].append(visits.prescriptions)
return context
The self in your DetailView is the PatientFile view object, not the Patient object.
You can however access the Patient object with self.object [Django-doc]:
class PatientFile(DetailView):
model = Patient
context_object_name = 'patient'
template_name = 'patient/file.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['prescriptions'] = prescriptions = []
for visit in self.object.visits.all():
prescriptions.extend(visit.prescriptions.all())
return context
Note that in order to iterate over a relation, you should use .all(), not just self.visits.

'__proxy__' object has no attribute 'get' in CreateView

So I'm thinking that this is not the right way to do things, but I am trying to learn django and I am trying some things out. I am trying to set a foreign key for my Formula model, by hardcoding in an instance of maker.
Models:
class Cooker(models.Model):
name = models.CharField(max_length=20, name="name")
background = models.CharField(max_length=500, name="background")
class Formula(models.Model):
food = models.CharField(max_length=200, name="food")
maker = models.ForeignKey(Cooker, related_name="cooker_key")
Views
class CookerCreate(CreateView):
template_name = "cookercreate.html"
model = Cooker
fields = ['name','background']
success_url = reverse_lazy('cooker')
class FormulaCreate(CreateView):
template_name = "formulahome.html"
model = Formula
fields = ['food']
success_url = reverse_lazy('formulahome')
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.maker = Cooker.objects.get(pk=1)
form.save()
return reverse_lazy('formula home')
In the FormulaCreate class where I am setting self.object.maker, I just want to hard code in a Cooker that I already created. Thanks
EDIT: When I try to submit the form in my FormulaCreate(CreateView) I get the error Exception Value: '__proxy__' object has no attribute 'get'
The reason for your error is that form_valid should return a Response object, and you are returning a URL.
Rather than do this manually you should just call the parent method which will redirect to the success_url that you have already defined:
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.maker = Cooker.objects.get(pk=1)
form.save()
return super(FormulaCreate, self).form_valid(form)
If you are using the post method return redirect('formula home') works too.

Adding foreign key to form

I have this model:
class Post(models.Model):
thread = models.ForeignKey(Thread)
post_title = models.CharField(max_length=50, blank=True)
# other attributes
And I have a view:
class ThreadView(CreateView):
model = models.Post
template_name = 'forum/thread.html'
fields = ['post_title', 'author', 'post_text']
When I try to send the form I get IntegrityError: NOT NULL constraint failed: forum_post.thread_id.
I think, it's because I foreign key remains empty, but I don't know how to add it automatically.
First, the name of the view you have is not quiet obvious, cause you are trying to create an instance of a Post not of a Thread. Won't it be better to rename it to PostCreateView?
Speaking about the error you get, you are right about foreign key - it is empty. After all, you do not set it anywhere. You should either send it in the form or assign it on validation. The second way is what you are looking for:
class ThreadView(CreateView):
model = models.Post
template_name = 'forum/thread.html'
fields = ['post_title', 'author', 'post_text']
def dispatch(self, *args, **kwargs):
self.thread = get_object_or_404(Thread, pk=kwargs['thread_id'])
return super(ThreadView, self).dispatch(*args, **kwargs)
def form_valid(self, form):
form.instance.thread = self.thread
return super(ThreadView, self).form_valid(form)
I think you must add ForeginKey Feild into Views Feilds
fields = ['thread', 'post_title', 'author', 'post_text']
and be sure there is a data in thread model
Try adding this to your view:
def post(self, *args, **kwargs):
self.t_id = kwargs["t_id"]
return super(ThreadView, self).post(*args, **kwargs)
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.thread = Thread.objects.get(pk=self.t_id)
form.save_m2m()
return super(ModelFormMixin, self).form_valid(form)

Categories