Django Forms - Declarative Fields Meta class is not iterable - django

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

Related

__init__() missing 1 required keyword-only argument: 'creator'

I am getting type error while setting current user to created_by field in my model
forms.py
class MyModelForm(forms.ModelForm):
class Meta:
model = Model
fields = ('name',)
def __init__(self, *args, creator, **kwargs):
super().__init__(*args, **kwargs)
self.creator = creator
def save(self, *args, **kwargs):
self.instance.created_by = self.creator
return super().save(*args, **kwargs)
views.py
class CreatEEView(LoginRequiredMixin, CreateView,):
form_class = ''
template_name = ''
success_url = ''
Models.py
class MYmodel(models.Model):
name = models.CharField()
created_by = models.ForeignKey()
You do not need to use a custom form for that because CreateView is creating ModelForm for you, what you can do is like that:
from django.db import models
class MYmodel(models.Model):
name = models.CharField()
created_by = models.ForeignKey()
Then you can override the form_valid method. This method is called when valid form data has been POSTed.
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView
from myapp.models import MYmodel
class CreatEEView(LoginRequiredMixin, CreateView):
model = MYmodel
fields = ['name']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
You can find the same example in Django documents in this Link

Use Form.has_changed() validation with Django UpdateView

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

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

Widgets in inlineformset_factory

Hey i managed to make a inlineformset_factory but my widget in the Parent Model are not working although i have specified them in the ModelForm .
My forms.py :
class PostForm(forms.ModelForm):
post = forms.CharField(widget=CKEditorWidget())
class Meta:
model = Post
fields = ['title', 'author','picture','post','draft','publish']
class PostVocabForm(forms.ModelForm):
class Meta:
model = PostVocab
exclude = ()
PostVocabInlineFormSet = inlineformset_factory(
Post,
PostVocab,
extra=1,
exclude=(),
)
My CKEditorWidget is not working ....
My views.py:
class PostPostVocabCreate(CreateView):
model = Post
form_class = PostForm
# fields = ['title', 'author', 'picture', 'post', 'draft', 'publish']
def get_redirect_url(self, pk):
return reverse_lazy('blog:post_detail',
kwargs={'slug': pk},
)
def get_context_data(self, **kwargs):
data = super(PostPostVocabCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['postvocabs'] = PostVocabInlineFormSet(self.request.POST)
else:
data['postvocabs'] = PostVocabInlineFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
postvocabs = context['postvocabs']
with transaction.atomic():
self.object = form.save()
if postvocabs.is_valid():
postvocabs.instance = self.object
postvocabs.save()
return super(PostPostVocabCreate, self).form_valid(form)
I guess that my widget from the Parent model (Post) was overwritten while using a inlineformset_factory...
You can set widgets inside of inlineformset_factory.
PostVocabInlineFormSet = inlineformset_factory(
Post,
PostVocab,
extra=1,
exclude=(),
widgets={'post': CKEditorWidget()
)
From Django docs...inlineformset_factory uses modelformset_factory and passes most of its arguments to modelformset_factory. This means you can use the widgets parameter in much the same way as passing it to modelformset_factory.
AuthorFormSet = modelformset_factory(
... Author, fields=('name', 'title'),
... widgets={'name': Textarea(attrs={'cols': 80, 'rows': 20})})`

Manually register user with FormWizard and django-registration

I have a UserModel and a UserProfile Model and I would like to use FormWizard from the formtools to both register the user and setup a userprofile with necessary inputs from the user.
I am struggling with some concepts and trying to patch this together with no success so far.
I get the error message:
AttributeError at /accounts/register/
'MyRegistrationView' object has no attribute 'request'
forms.py
class UserForm(forms.ModelForm):
password1 = forms.CharField(widget=forms.PasswordInput())
password2 = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2', 'first_name', 'last_name')
class UserProfileForm(forms.ModelForm):
course_accid = CourseModelChoiceField(Course.objects.all(), empty_label=None)
class Meta:
model = UserProfile
fields = ('picture','reg_completed')
url.py
urlpatterns = solid_i18n_patterns ('',
url(r'^accounts/register/$', RegistrationWizard.as_view([UserForm, UserProfileForm]), name='registration_register'),
url(r'^accounts/', include('registration.backends.simple.urls')),
views.py
from formtools.wizard.views import SessionWizardView
from registration.signals import *
from django.core.files.storage import FileSystemStorage
from django.conf import settings
class MyRegistrationView(RegistrationView):
def get_success_url(self, user):
return '/index/'
TEMPLATES = {"0": "registration/registration_form_wiz.html",
"1": "registration/registration_form_wiz.html",
}
class RegistrationWizard(SessionWizardView):
form_list = [UserForm, UserProfileForm]
file_storage = FileSystemStorage(location=settings.MEDIA_ROOT + '/photos')
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
userreg = MyRegistrationView()
for form in form_list:
if isinstance(form, UserForm):
userreg.register(form)
elif isinstance(form, UserProfileForm):
userprofile = form.save(commit=False)
user = self.request.user
userprofile.user = user
userprofile.save()
return HttpResponseRedirect('/index/')
Any help for what is wrong or if another approach would be better, is very welcome.
Thanks!