Use Form.has_changed() validation with Django UpdateView - django

I am trying to post a message when one or more of the values have changed in an UpdateView. Is this possible to do with Form.has_changed() with this generic view? For example:
class MyUpdateView(UpdateView):
model = MyModel
form = MyModelForm
fields = "__all__"
template_name = "mymodel_form.html"
if form.has_changed():
logger.info("Some values have changed")

You can override the .form_valid(…) method [Django-doc] for this:
class MyUpdateView(UpdateView):
model = MyModel
form_class = MyModelForm
fields = '__all__'
template_name = 'mymodel_form.html'
def form_valid(self, form):
if form.has_changed():
logger.info('Some values have changed')
return super().form_valid(form)
or if you want to log changes if the form might be invalid as well, you can use .get_form(…) [Django-doc]:
class MyUpdateView(UpdateView):
model = MyModel
form_class = MyModelForm
fields = '__all__'
template_name = 'mymodel_form.html'
def get_form(self, form_class=None):
form = super().get_form(form_class=form_class)
if form.has_changed():
logger.info('Some values have changed')
return form

Related

Django Forms - Declarative Fields Meta class is not iterable

Why django throws me an error TypeError at /primary argument of type DeclarativeFieldsMetaclass is not iterable.
I'm trying to work with django-forms for the first time, after i added this into my forms.py file, it keeps showing me the error message saying: TypeError at /primary argument of type 'DeclarativeFieldsMetaclass' is not iterable, how can i solve this problem?
Forms.py
from django import forms
from .models import Primary, PrimaryAlbum, Secondary, SecondaryAlbum
from jsignature.forms import JSignatureField
from jsignature.widgets import JSignatureWidget
class PrimaryForms(forms.Form):
signature_of_student = JSignatureField(
widget=JSignatureWidget(
jsignature_attrs={'color':'#e0b642', 'height':'200px'}
)
)
class Meta:
model = Primary
fields = ['admission_number', 'profile_picture', 'first_name',
'last_name', 'gender', 'address_of_student', 'class_Of_student', 'signature_of_student']
Views.py
from .forms import PrimaryForms
class CreatePrimaryStudent(LoginRequiredMixin, CreateView):
model = Primary
fields = PrimaryForms
template_name = 'create_primary_student_information.html'
success_url = reverse_lazy('Home')
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['year_of_graduation'].queryset = PrimaryAlbum.objects.filter(user=self.request.user)
return form
def form_valid(self, form):
form.instance.user = self.request.user
return super(CreatePrimaryStudent, self).form_valid(form)
I solve my problem by changing it from fields = PrimaryForms to form_class in views.py file under CreatePrimaryStudent class, and for forms.py file, I change the class method from: class PrimaryForms(forms.Form): to class PrimaryForms(forms.ModelForm):
forms.py
class PrimaryForms(forms.ModelForm):
signature_of_student = JSignatureField(
widget=JSignatureWidget(
jsignature_attrs={'color':'#e0b642', 'height':'200px'}
)
)
signature_of_guardian = JSignatureField(
widget=JSignatureWidget(
jsignature_attrs={'color':'#e0b642', 'height':'200px'}
)
)
class Meta:
model = Primary
fields = ['admission_number', 'profile_picture', 'first_name',
'last_name', 'gender', 'address_of_student', 'class_Of_student', 'signature_of_student']
Views.py
class CreatePrimaryStudent(LoginRequiredMixin, CreateView):
model = Primary
form_class = PrimaryForms
template_name = 'create_primary_student_information.html'
success_url = reverse_lazy('Home')
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['year_of_graduation'].queryset = PrimaryAlbum.objects.filter(user=self.request.user)
return form
def form_valid(self, form):
form.instance.user = self.request.user
return super(CreatePrimaryStudent, self).form_valid(form)
Django Docs

Django DetailView form dont save data

I have a DetailView, and need add a form to user contact.
views.py
class ProductView(FormView, DetailView):
model = Product
template_name = 'product_detail.html'
form_class = NotificationForm
success_url = '/products/'
def post(self, request, *args, **kwargs):
return FormView.post(self, request, *args, **kwargs)
forms.py
class NotificationForm(ModelForm):
..."""some fields"""
class Meta:
model = Notification
fields = [
'usernameclient',
'emailclient',
'emailclient_confirmation',
'phoneclient',
'messageclient',
]
The model Notification is where is stored the data from that form
models.py
class Notification(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
..."""some fields"""
I dont understand yet how django workflow with forms. After the submition is correct rediretc to success_url, but nothing is save in db... What is missing?
A FormView does not save the form, a CreateView does. You can save the form with:
class ProductView(FormView, DetailView):
model = Product
template_name = 'product_detail.html'
form_class = NotificationForm
success_url = '/products/'
def form_valid(self, form):
form.save()
return super().form_valid(form)

Django Improved UpdateView?

I have this UpDateView class and I need just author of article can edit the blog .I had the solution for the CreateView class(using def Form_valid) but it doesn't work for UpdateView class :::
class ArticleUpdateView(LoginRequiredMixin,UpdateView):
model = models.Article
template_name = 'article_edit.html'
fields = ['title','body']
login_url = 'login'
class ArticleCreateView(LoginRequiredMixin,CreateView):
model = models.Article
template_name = 'article_new.html'
fields = ['title','body',]
login_url='login'
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
You can override the get_object method in your view class:
class ArticleUpdateView(LoginRequiredMixin,UpdateView):
model = models.Article
template_name = 'article_edit.html'
fields = ['title','body']
login_url = 'login'
def get_object(self, *args, **kwargs):
article = super().get_object(*args, **kwargs)
if article.author != self.request.user:
raise PermissionDenied('You should be the author of this article.')
return article

Populating a FormView with custom queryset

I'd like to set the logged in user's data to a profile form. Why isn't the below view populating the model form?
class UpdateProfile(FormView):
model = User
form_class = ProfileForm
def get_queryset(self):
return self.model.objects.get(pk=self.request.user.id)
class ProfileForm(forms.ModelForm):
class Meta:
model = User
fields = ['email', 'name', 'company', 'title']
All my fields end up empty.
For single object views, you need to override get_object and use an UpdateView.
So to get the logged in user you could do:
from django.views.generic import UpdateView
class UpdateProfile(UpdateView):
model = User
form_class = ProfileForm
def get_object(self):
return self.request.user

Save m2m in FormView django

I'm trying to save a m2m field in a FormView.
Here is my code:
class ProductorPropietarioView(FormView):
form_class = FormPropietario
success_url = '/'
template_name = 'productores/propietario.html'
def form_valid(self,form):
form.save(commit=False)
form.save()
form.save_m2m()
return super(ProductorPropietarioView,self).form_valid(form)
models.py
class Persona(models.Model):
predio = models.ForeignKey(InfoPredioGeneral,related_name='predio+')
rol = models.ManyToManyField(RolPersona)
tipo_identificacion = models.ForeignKey(TipoIdentificacion,related_name='tipo identificacion+',blank=True,null=True)
numero_identificacion = models.CharField(max_length=100,blank=True,null=True)
forms.py
class FormPropietario(ModelForm):
class Meta():
model = Persona
fields = '__all__'
I can't get this to work. I know that first I have to set False then save the form and then save the m2m. I already tried only with form.save()
What am I doing wrong?
Try changing your FormView as follows:
def form_valid(self,form):
f = form.save(commit=False)
f.save()
form.save_m2m()
return super(ProductorPropietarioView,self).form_valid(form)