I am trying to bind my FormView to show the Form in djangocms but i am not able to - django-cms

I am trying to bind my FormView to show the Form in djangocms but I am not able to,
my model is:
class ContactFormView(FormView, CMSPlugin):
template = '/ContactForm/ContactForm.html'
form_class = contact_form
success_url = reverse_lazy('success-page')
def post(self, request, **kwargs):
assert request.is_ajax()
request_data = json.loads(request.body)
form = self.form_class(data=request_data[self.form_class.scope_prefix])
if form.is_valid():
return JsonResponse({'success_url': force_text(self.success_url)})
else:
response_data = {form.form_name: form.errors}
return JsonResponse(response_data, status=422)
cms_plugins.py:
class ContactFormPlugin(CMSPluginBase):
model = ContactForm.ContactFormView
render_template = '/ContactForm/ContactForm.html'
name = 'Contact Form'
allow_children = False
plugin_pool.register_plugin(ContactFormPlugin)

Looking at what you've got there, I'm not sure you've given your plugin a proper model but a view!? And the form class isn't a form class, form_class = contact_form but what is contact_form? You need it to be the class of your form e.g.
class ContactForm(forms.Form):
name = forms.CharField(label='Your name', max_length=100)
email = forms.EmailField(label='Your email', max_length=100)
class ContactFormView(FormView):
template = '/ContactForm/ContactForm.html'
form_class = ContactForm
success_url = reverse_lazy('success-page')
And if you've got a form you want your plugin to render, you need to tell it what to do...
from cms.models.pluginmodel import CMSPlugin
class ContactFormPlugin(CMSPluginBase):
model = CMSPlugin
render_template = '/ContactForm/ContactForm.html'
name = 'Contact Form'
allow_children = False
def render(self, context, instance, placeholder):
context = super(ContactFormPlugin, self).render(context, instance, placeholder)
context['form'] = ContactForm()
return context
However you're working with a CMS plugin, so you don't define a View at all for a plugin. I think you could make this do what you're trying to do but the view doesn't want to inherit CMSPlugin because you just want a view to receive data from the plugin.
If you need to define views then you're building an app which in CMS requires an Apphook, not a plugin. (Technically you could post to a URL without an Apphook, but depends how much CMS integration you want)
There is a great example that starts with a plugin posting to a view then progresses into the app integration which is possible here; http://docs.django-cms.org/en/latest/introduction/plugins.html

Related

How to Save Currently Logged in User to Model in Django

I am trying to get the currently logged in User and save it to a model. I am getting the following error
"Cannot assign "<SimpleLazyObject: <User: rsomani005>>": "process_master.user" must be a "User" instance"
I am using Django's built in user model.
My model looks like this -
class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
return "#{}".format(self.username)
class plan_master(models.Model):
plan_name = models.CharField(max_length=256)
plan_description = models.CharField(max_length=256)
plan_price = models.FloatField()
plan_active_status = models.BooleanField(default=True)
plan_credits = models.IntegerField(default=0)
registration_type_name = models.CharField(max_length=50)
My view file looks like this -
class FileFieldView(LoginRequiredMixin,FormView):
form_class = FileFieldForm
template_name = 'merge_ops/merge_ops.html'
success_url = reverse_lazy('merge_ops:file_setup')
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
fs = FileSystemStorage()
fs.save(f.name,f)
obj = process_master()
user = request.user
obj.user = user
obj.process_date = datetime.now()
obj.number_of_workbooks = len(files)
obj.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
An easy way to get the logged user in one of your views is:
user = request.user
but that is usually when the user model that you have created is something like that in the model.py:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
I would suggest using this one to register users because it is automatic and complete.
and from there use the object for what you need. You can pass it on as a context or
source model objects from it.

Django CMS plugin nesting --- child doesn't show up in the "structure" interface

I'm trying to create a Django CMS custom plugin that can assemble other plugins.
As far as I can tell, Django CMS can do this using Plugin nesting, and I've followed the examples to create a simple test case.
My expectation is that when you go into the "Structure" tab for a record in the model that has a PlaceholderField that includes the parent plugin, when you add a parent plugin, the pop-up for that model should ALSO have some way to edit/create/add an instance of the child plugin. But it doesn't --- all I see are the fields for the parent plugin and NOTHING about the children (see screenshot below).
Or am I missing the point of Plugin nesting entirely?
models.py:
from django.db import models
from cms.models import CMSPlugin
from cms.models.fields import PlaceholderField
from djangocms_text_ckeditor.models import AbstractText
class CustomPlugin(CMSPlugin):
title = models.CharField('Title', max_length=200, null=False)
placeholder_items = PlaceholderField ('custom-content')
renderer = models.CharField('Renderer', max_length=50, null=True, blank=True,
help_text='This is just to show that a custom renderer CAN be done here!')
class ChildTextPlugin(AbstractText):
pass
cms_plugins.py:
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from django.utils.translation import ugettext as _
from .models import CustomPlugin, ChildTextPlugin
class CMSCustomPlugin(CMSPluginBase):
model = CustomPlugin
name = _('Custom Plugin')
render_template = 'custom/custom_plugin.html'
allow_children = True
def render(self, context, instance, placeholder):
context = super(CMSCustomPlugin, self).render(context, instance, placeholder)
return context
class CMSChildTextPlugin(CMSPluginBase):
model = ChildTextPlugin
name = _('Child Text Plugin')
render_template = 'custom/child_text_plugin.html'
parent_classes = ['CMSCustomPlugin',]
def render(self, context, instance, placeholder):
context = super(ChildTextPlugin, self).render(context, instance, placeholder)
return context
plugin_pool.register_plugin(CMSCustomPlugin)
plugin_pool.register_plugin(CMSChildTextPlugin)
... and the answer is "it was working all the time" --- the interface comes AFTER the screen I posted above is submitted --- the Custom Plugin entry will have a "+" icon, and it's THERE that the children are found.

How to customize z3c.form widget for fields inside groups (fieldsets)

I have a Plone custom control panel registry and I'm trying to use a well know method to customize some of the widgets properties for zope.schema.Text and zope.schema.TextField.
I commonly customize the updateWidgets in that way:
def updateWidgets(self):
super(MyEditForm, self).updateWidgets()
self.widgets['my_text_area'].style = 'width: 100%'
self.widgets['my_text_area'].rows = 7
But now I'm working on a form where fields are splitted in two fieldsets:
class MySettingsEditForm(controlpanel.RegistryEditForm):
schema = IMySettingsSchema
groups = (Form1, Form2)
# fields = nothing
If I try to access self.widgets['my_text_area'] I get KeyError. It seems that as I did't defined the fields attribute I can't access directly widgets.
I found that I have groups so I can call something like self.groups[0].fields['my_text_area'] but still I find no way to access widgets for fields inside groups.
How can I customize widgets attributes when using groups?
I think what you need is playing with widget subform, see this code:
def fix_table_widget(self, name, widgets):
sub_widgets = widgets[name].widgets
for widget in sub_widgets:
new_label = widget.subform.widgets['weekday'].value
widget.subform.widgets['selected'].items[0]['label'] = new_label
widget.subform.widgets['weekday'].mode = 'hidden'
def schoolrequest_customizations(self):
''' Customizations for the schoolrequest base views
'''
for group in self.groups:
widgets = group.widgets
if 'table_bus_to_school' in widgets:
self.block_widget_table('table_bus_to_school', widgets)
self.fix_table_widget('table_bus_to_school', widgets)
if 'table_bus_to_home' in widgets:
self.block_widget_table('table_bus_to_home', widgets)
self.fix_table_widget('table_bus_to_home', widgets)
def update(self):
super(MyForm, self).update()
self.schoolrequest_customizations()

How could I render just the form from an autoform?

I'm in the context of a BrowserView. I want to render a form inside the page.
class CommandeView(BrowserView):
...
def render_myform(self):
livraison_form = LivraisonForm(self.context, self.request)
livraison_form.update()
return livraison_form.render()
class ILivraisonForm(interface.Interface):
livraison = schema.Choice(title=_(u"Mode de livraison"),
vocabulary=livraison_vocabulary)
class LivraisonForm(AutoExtensibleForm, form.EditForm):
schema = ILivraisonForm
class LivraisonFormAdapter(object):
component.adapts(ICommande)
interface.implements(ILivraisonForm)
def __init__(self, context):
self.context = context
self.livraison = self.context.livraison
I would like render_myform to render only the form but it return a HTML Plone page.
Any tips are welcomed.
Haven't checked this in-depth, but the form is probably wrapped by the plone FormWrapper class.
Look for a .form attribute on the LivraisonForm instance:
def render_myform(self):
livraison_form = LivraisonForm(self.context, self.request).form
livraison_form.update()
return livraison_form.render()
It may be you need to add an additional interface to the request for this to work (the wrapper normally does this for you. I'm a little low on time right now, so you get this untested:
from plone.z3cform import z2
class CommandeView(BrowserView):
def render_myform(self):
z2.switch_on(self) # Apply layer interface, set up locale, add `getURL` method
livraison_form = LivraisonForm(self.context, self.request).form
livraison_form.update()
return livraison_form.render()
The Plone Knowledgebase uses this same setup to show a form in a viewlet.

relating models to one another using generic views

I'm new to Django and programming in general. I'm trying to make a simple site that allows players of a sport sign up for leagues that have been created by the admin. In my models.py, I created two models:
from django.db import models
from django.forms import ModelForm
class League(models.Model):
league_name = models.CharField(max_length=100)
pub_date = models.DateTimeField('date published')
class Info(models.Model):
league = models.ManyToManyField(League)
name = models.CharField(max_length=50)
phone = models.IntegerField()
email = models.EmailField()
def __unicode__(self):
return self.info
class InfoForm (ModelForm):
class Meta:
model = Info
exclude = ('league')
From what I've read, I can probably use the Create/Update/Delete generic views to display a form for the user to sign up for the league. So with my app, I want the user to come to a simple homepage that lists the leagues, be able to click on the league and enter their info to sign up. Here's what my urlconf looks like:
from django.conf.urls.defaults import *
from mysite.player_info.models import League, Info, InfoForm
info_dict = {
'queryset': League.objects.all(),
}
InfoForm = {'form_class' : InfoForm}
urlpatterns = patterns('',
(r'^$', 'django.views.generic.list_detail.object_list', info_dict),
(r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),
url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='player_info/results.html'), 'league_results'),
(r'^(?P<object_id>\d+)/info/create/$', 'django.views.generic.create_update.create_object', InfoForm),
)
Here's my problem: When I click on a league to sign up for on the homepage with my current setup, I get this error: TypeError at /league/1/info/create.... create_object() got an unexpected keyword argument 'object_id'. What am I doing wrong?
The issue isn't with your models, but rather with the function your "create" URL calls -- the line that calls django.views.generic.create_update.create_object() in urls.py. create_object() doesn't take an object_id argument, but you specified one in your url (r'^(?P<object_id>\d+)/info/create/$'). This makes sense -- you're creating an object, so you don't know its ID yet. create_object() only takes a form_class or model argument, as noted in the docs.
I'm guessing you're trying to create an Info object that is attached to a League object, and in that URL, <object_id> is the ID number of the League object; in which case, you shouldn't name that ID number, and instead should just use r"^\d+/info/create/$" as the URL. I'm not sure how you'll grab the league ID number using Django's create_object() function, though. You might have to write your own view handler. You may be able to use a custom ModelForm and pass it in with the form_class parameter, but I'm not sure.

Resources