How to let the objects be changed just by his creator - python

I've got a project where the user can create a model Parceiros and in that model is a model linking all the Servicos to that model Parceiros. The problem is that the Parceiros should be linked to the current user as the only way to create a Parceiros object is logging in before. After that the only user that should be able to change the Parceiros fields or Servicos should be the current user that created o Parceiros object.
I've read some questions and tried with context processors, but didn't manage to get the Parceiros linked to the user.
services/models.py
from django.db import models
from phone_field import PhoneField
from datetime import datetime
from django.contrib.auth import get_user_model
from django.template.defaultfilters import slugify
User = get_user_model()
class Parceiros (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
nome = models.CharField(max_length=200)
endereco = models.TextField(max_length=400, blank=True)
responsavel = models.CharField(max_length=100)
tel = PhoneField(max_length=12)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now_add=True, blank=True)
ativo = models.BooleanField(default=False)
class Servicos (models.Model):
tipo = models.CharField(max_length=200)
objetivo = models.TextField(max_length=500, blank=True)
parceiro = models.ForeignKey(Parceiros, on_delete=models.CASCADE)
preco = models.DecimalField(max_digits=9, decimal_places=2, blank=True)
telefone = PhoneField(max_length=12, default='21968151502')
def get_image_filename(instance, filename):
tipo = instance.services.tipo
slug = slugify(tipo)
return "servicos_imagens/%s-%s" % (slug, filename)
class Imagens (models.Model):
servicos = models.ForeignKey(Servicos, on_delete=models.CASCADE)
imagem = models.ImageField(upload_to=get_image_filename)
services/views.py
from django.shortcuts import render, redirect
from .models import Servicos, Parceiros, Imagens
from django.views.generic import UpdateView, DetailView, ListView
from .forms import ParceirosForm, ServicosForm, ImagensForm
from django.contrib.auth.decorators import login_required
from django.contrib.auth.context_processors import auth
def home_view(request):
serv = Servicos.objects.all()
context = {'serv': serv }
return render (request, 'home.html', context)
#login_required
def parceiros_create(request):
if request.method =='POST':
form = ParceirosForm(request.POST)
Parceiros.user = auth.user
if form.is_valid():
parceiro = form.save(commit=False)
parceiro.save()
return redirect('home2')
else:
form = ParceirosForm()
context = {
'form': form,
}
return render (request, 'parceiroform.html', context)
def parceirosview(request):
user = Servicos.parceiro
serv = Servicos.objects.get(parceiro=user)
context = {'serv': serv}
return render(request, 'parceiro.html', context)
class ServicoView(DetailView):
model = Servicos
class ServicoUpdate(UpdateView):
model = Servicos
template_name = 'servicoform.html'
services/forms.py:
from django import forms
from .models import Servicos, Imagens, Parceiros
from phone_field import PhoneField
class ParceirosForm(forms.ModelForm):
class Meta:
prefix = 'parceiro'
model = Parceiros
fields = ['nome', 'endereco', 'responsavel', 'tel']
class ServicosForm(forms.ModelForm):
tipo = forms.CharField(max_length=200)
objetivo = forms.CharField(max_length=500)
preco = forms.DecimalField(max_digits=9, decimal_places=2)
telefone = PhoneField(max_length=12)
class Meta:
prefix = 'service'
model = Servicos
fields = ['tipo', 'objetivo', 'preco', 'telefone']
class ImagensForm(forms.ModelForm):
imagem = forms.ImageField(label='image')
class Meta:
model = Imagens
fields = ['imagem']

Parceiros is the class, so Parceiros.user = auth.user doesn't do anything.
When saving your form, you should assign the user to the actual instance of the model you're saving:
if form.is_valid():
parceiro = form.save(commit=False)
parceiro.user = request.user # assuming user is a FK field on Parceiros
parceiro.save()
Note that you should use request.user (not auth.user) which is the currently logged in user.
For the UpdateViews, you only need to change the queryset in order to ensure that only instances belonging to that user can be changed:
# inside class ServicoUpdate
# Servico is related to User via the Parceiros model
def get_queryset(self):
return super().get_queryset().filter(parceiro__user=self.request.user)
# inside class ParceiroUpdate
def get_queryset(self):
return super().get_queryset().filter(user=self.request.user)
And similarly for any other view that requires to restrict access to only the current logged in user's instances, if using a class-based view, override get_queryset().

Related

How to let the user add as many forms as they want to a ModelForm that saves to the same model in django

I have a form to let users make a new poll, it consists of 2 ModelForms one for the Question model and another for the Choice model
a screenshot:
Make new poll form
i want there to be something like a (+) or (add another choice) button where users can add as many choices as they want and then submit it all.
here's the models.py file
models.py
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Question(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
questionText = models.CharField(max_length=150)
datePublished = models.DateTimeField(auto_now_add=True)
def str(self):
return self.questionText
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choiceText = models.CharField(max_length=200)
choiceVotes = models.IntegerField(default=0)
def str(self):
return self.choiceText
forms.py
from django import forms
from .models import Question
from .models import Choice
class NewPollForm(forms.ModelForm):
class Meta:
model = Question
labels = {
"questionText":"Poll question"
}
fields = ("questionText",)
class NewChoicesForm(forms.ModelForm):
class Meta:
model = Choice
labels = {
"choiceText":"Choice"
}
fields = ("choiceText",)
the view for this form's page you can see it is set for only one choice field right now
from .forms import NewPollForm
from .forms import NewChoicesForm
def newpoll(request):
if request.user.is_authenticated == True :
pass
else:
return redirect("users:signup")
if request.method == "POST":
qform = NewPollForm(request.POST)
cform = NewChoicesForm(request.POST)
if qform.is_valid():
newpoll = qform.save(commit=False)
newpoll.user = request.user
newpoll.datePublished = timezone.now()
newpoll.save()
cform.instance.question = newpoll
cform.save()
return redirect("polls:details", pollid=newpoll.pk)
else:
return render (request, "polls/newpoll.html", {"qform":qform, "cform":cform})
else:
qform = NewPollForm()
cform = NewChoicesForm()
return render (request, "polls/newpoll.html", {"qform":qform, "cform":cform})

error in Django RestFrameWork "NOT NULL constraint failed: qoura_question.author_id "

trying to add a post to DRF which takes the information of USER and TIME automatically, But this is the error which pops up when tried to add a Post.
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length = 200)
description = models.CharField(max_length = 2000)
date_posted = models.DateTimeField(default = timezone.now)
author = models.ForeignKey(User , on_delete = models.CASCADE)
def __str__(self):
return self.title
Views.py:
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
authentication_classes = [TokenAuthentication,SessionAuthentication]
def create(self, request):
obj = Post()
obj.title = request.data['title']
obj.description = request.data['description']
obj.date_posted = request.data['date_posted']
obj.user = request.user
obj.save()
return Response(status=status.HTTP_201_CREATED)
serializer.py:
from rest_framework import serializers
from django.contrib.auth.models import User
from . models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('id', 'title','description','date_posted','author')

AssertionError: The field 'links' was declared on serializer SprintSerializer, but has not been included in the 'fields' option

I am having problems with reproducing example from Julia Elman's book
models.py
class Sprint(models.Model):
name = models.CharField(max_length=100, blank=True, default='')
description = models.TextField(blank=True, default='')
end = models.DateField(unique=True)
def __str__(self):
return self.name or _('Sprint ending %s') % self.end
serializer.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from rest_framework.reverse import reverse
from .models import Sprint, Task
User = get_user_model()
class SprintSerializer(serializers.ModelSerializer):
links = serializers.SerializerMethodField('get_links')
class Meta:
model = Sprint
fields = ('id', 'name', 'description', 'end', 'links',)
def get_links(self, obj):
request = self.context['request']
return {'self': reverse('sprint-detail',kwargs={'pk': obj.pk},request=request),}
views.py
from django.contrib.auth import get_user_model
from rest_framework import authentication, permissions, viewsets
from .models import Sprint,Task
from .serializers import SprintSerializer,TaskSerializer, UserSerializer
User = get_user_model()
class DefaultsMixin(object):
authentication_classes = (authentication.BasicAuthentication,authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
paginate_by = 25
paginate_by_param = 'page_size'
max_paginate_by = 100
class SprintViewSet(DefaultsMixin, viewsets.ModelViewSet):
queryset = Sprint.objects.order_by('end')
serializer_class = SprintSerializer
I try to see repr from shell
from board.serializers import SprintSerializer
>>> s = SprintSerializer()
>>> print (repr(s))
But I have problem
AssertionError: The field 'links' was declared on serializer SprintSerializer, but has not been included in the 'fields' option.
My DRF
print (rest_framework.VERSION)
3.8.2
How to debug this issue?
Yes,what Alexandr Tartanov suggested works fine.We need to pass arguments with source
links = serializers.SerializerMethodField(source='get_links')
Output
print (repr(s))
SprintSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(allow_blank=True, max_length=100, required=False)
description = CharField(allow_blank=True, required=False, style={'base_template': 'textarea.html'})
end = DateField(validators=[<UniqueValidator(queryset=Sprint.objects.all())>])
links = SerializerMethodField(source='get_links')

Filtering the options of ModelChoiceField in forms in django as per the ForeignKey relations

In my django project, I created three model classes. The class 'Subtopic' has ForeignKey relation with class 'Chapter' and class 'SAQ' has ForeignKey relation with class 'Chapter' and class 'Subtopic'.
#models.py
from django.db import models
class Chapter(models.Model):
chapter_serial = models.IntegerField(null=False, help_text="Chapter No.")
slug = models.SlugField(unique=True, blank=True)
chapter_name = models.CharField(max_length=120)
class Meta:
ordering = ["chapter_serial"]
def get_saq_list_url(self):
return reverse("cms:saq_list", kwargs={"chap_slug":self.slug})
class Subtopic(models.Model):
subtopic_serial = models.IntegerField(null=False)
title = models.CharField(max_length=240)
chapter = models.ForeignKey('Chapter', on_delete=models.CASCADE)
class Meta:
ordering = ["subtopic_serial"]
class SAQ(models.Model):
question_serial = models.IntegerField(null=False)
question = models.TextField()
answer = models.TextField()
chapter = models.ForeignKey('Chapter', on_delete=models.CASCADE)
subtopic = models.ForeignKey('Subtopic', on_delete=models.CASCADE, null=True, blank=True)
class Meta:
ordering = ["question_serial"]
I tried to create forms using django ModelForm for 'model SAQ' such that for each 'SAQ form' associated with a particular chapter instance, the choice field for model 'Subtopic' will contain only those subtopics of that particular chapter instance.
#forms.py
from django import forms
from .models import SAQ
class SAQForm(forms.ModelForm):
class Meta:
model = SAQ
fields = [
'question_serial',
'question',
'answer',
'important',
'remarks',
'subtopic',
]
The django view function to create the form is as below.
from django.shortcuts import render, get_object_or_404, redirect
from .models import SAQ, Chapter, Subtopic
from .forms import SAQForm
from django.http import HttpResponseRedirect
def saq_create(request, chap_slug=None):
chapter_instance = get_object_or_404(Chapter, slug=chap_slug)
form = SAQForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.chapter = chapter_instance
instance.save()
return HttpResponseRedirect(chapter_instance.get_saq_list_url())
context = {
"form":form,
"chapter_instance":chapter_instance,
}
return render(request, 'cms/saq_form.html', context)
With this configuration, the choice field in the form, for 'Subtopic' shows all subtopics for all chapter instances. Any suggestion would be very helpful.
I would suggest to override the form init and pass the chapter instance so you can filter the subtopic queryset.
Example (not tested, could contain typos):
#forms.py
from django import forms
from .models import SAQ
class SAQForm(forms.ModelForm):
class Meta:
model = SAQ
fields = [
'question_serial',
'question',
'answer',
'important',
'remarks',
'subtopic',
]
def __init__(self, chapter, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['subtopic'].queryset = \
self.fields['subtopic'].queryset.filter(chapter=chapter)
And then your view should pass the chapter instance to the form:
chapter_instance = get_object_or_404(Chapter, slug=chap_slug)
form = SAQForm(chapter_instance, request.POST or None)

Django Admin not saving data to the Database

I am trying to save data from my Django Admin to my database but somehow it is not happening. I have created a form in one of my apps which my admin uses.I am new to Django and any help would be greatly appreciated.
Below is the relevant code:
models.py
from __future__ import unicode_literals
from django.contrib.auth.models import User
from django_countries.fields import CountryField
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(max_length=100)
bio = models.TextField(max_length=1000, blank=True, null=True)
image = models.FileField()
country = CountryField()
city = models.CharField(max_length=100)
twitter = models.CharField(max_length=100, null=True, blank=True)
linkedin = models.CharField(max_length=100, null=True, blank=True)
location = models.TextField()
def __unicode__(self):
return self.name
def __str__(self):
return self.name
class Mentor(models.Model):
mentor = models.CharField(max_length=100)
mentee = models.CharField(max_length=100)
def __unicode__(self):
return self.mentee
def __str__(self):
return self.mentee
forms.py
from django import forms
from models import UserProfile, Mentor
from django_countries.fields import CountryField
from django.contrib.auth.models import User
from reports.models import Reports
class UserProfileForm(forms.ModelForm):
name = forms.CharField(max_length=100)
bio = forms.Textarea()
image = forms.FileField(label='Profile Photo')
country = CountryField(blank_label='(Select Country)')
city = forms.CharField(max_length=100)
twitter = forms.CharField(max_length=100, required=False)
linkedin = forms.CharField(max_length=100, required=False)
class Meta:
model = UserProfile
exclude = ('user',)
class MentorForm(forms.ModelForm):
mentor_choices = tuple(UserProfile.objects.filter(user__is_staff=1).order_by('name').values_list('name', 'name'))
mentee_choices = tuple(UserProfile.objects.exclude(user__is_staff=1).order_by('name').values_list('name', 'name'))
mentor_name = forms.ChoiceField(choices=mentor_choices)
mentee_name = forms.ChoiceField(choices=mentee_choices)
def save(self, commit=True):
mentor_name = self.cleaned_data.get('mentor_name', None)
mentor_name = self.cleaned_data.get('mentee_name', None)
return super(MentorForm, self).save(commit=commit)
class Meta:
model = Mentor
fields= ('mentor_name', 'mentee_name')
admin.py
from django.contrib import admin
from .models import UserProfile, Mentor
from.forms import MentorForm
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user',)
search_fields = ['user']
def save_model(self, request, obj, form, change):
obj.created_by = request.user
obj.save()
admin.site.register(UserProfile, UserProfileAdmin )
class MentorAdmin(admin.ModelAdmin):
list_display = ('__unicode__','mentee')
search_fields = ['mentee', 'mentor']
form = MentorForm
fieldsets = (
(None,{
'fields': ('mentor_name', 'mentee_name'),
}),
)
def save_model(self, request, obj, form, change):
super(MentorAdmin, self).save_model(request, obj, form, change)
admin.site.register(Mentor, MentorAdmin )
The UserProfile works perfectly but the Mentor form in admin doesn't save anything in the database. It creates blank entries into the database, so I know that the front and backend are talking but no data is being passed. Any help will be very helpful
def save(self, commit=True):
# here you define `mentor_name`. OK.
mentor_name = self.cleaned_data.get('mentor_name', None)
# here you redefine `mentor_name`. I guess it is a typo and should be `mentee_name`.
mentor_name = self.cleaned_data.get('mentee_name', None)
# And... you don't do anything with these variables.
return super(MentorForm, self).save(commit=commit)
This method is equivalent to:
def save(self, commit=True):
return super(MentorForm, self).save(commit=commit)
Which is equivalent to not overriding the save method at all.
And what about this?
def save_model(self, request, obj, form, change):
super(MentorAdmin, self).save_model(request, obj, form, change)
What is the purpose of overriding a method and only calling the parent method with the exact same arguments?
But the actual issue is here:
mentor_choices = tuple(UserProfile.objects.filter(user__is_staff=1).order_by('name').values_list('name', 'name'))
mentee_choices = tuple(UserProfile.objects.exclude(user__is_staff=1).order_by('name').values_list('name', 'name'))
mentor_name = forms.ChoiceField(choices=mentor_choices)
mentee_name = forms.ChoiceField(choices=mentee_choices)
class Meta:
model = Mentor
fields = ('mentor_name', 'mentee_name')
You use a ModelForm but none of the Mentor's fields is in fields. What are you expecting this to do other than saving a row with Mentor.mentor = None and Mentor.mentee = None. You don't even mention those fields.
And why are you using CharField for Mentor.mentor and Mentor.mentee while you likely want a foreign key.
class Mentor(models.Model):
mentor = models.ForeignKey(UserProfile, models.PROTECT,
related_name='mentees')
mentee = models.ForeignKey(UserProfile, models.PROTECT,
related_name='mentors')
class MentorForm(forms.ModelForm):
class Meta:
model = Mentor
fields = ('mentor', 'mentee')
mentor = forms.ModelChoiceField(queryset=UserProfile.objects.filter(
user__is_staff=True).order_by('name'))
mentee = forms.ModelChoiceField(queryset=UserProfile.objects.exclude(
user__is_staff=True).order_by('name'))
Or even better:
class Mentor(models.Model):
mentor = models.ForeignKey(
UserProfile, models.PROTECT, related_name='mentees',
limit_choices_to={'user__is_staff': True},
)
mentee = models.ForeignKey(
UserProfile, models.PROTECT, related_name='mentors',
limit_choices_to={'user__is_staff': False},
)
Which avoids you to create a form.

Categories

Resources