z3c.form add fields dynamically an catalog.results - plone

How can I dynamically add form fields, depending on catalog.results?
For Example:
catalog.results = ['Channel A', 'Channel B', 'Channel C',]
form.fields should be
form.fieldset Channels A {
input[type=checkbox].course a1
input[type=checkbox].course a2
input[type=checkbox].course a3
}
form.fieldset Channels B {
input[type=checkbox].course b1
input[type=checkbox].course b2
input[type=checkbox].course b2
}
Every Channel is folderish, and every Channel can contain N courses, for each channel should be a fieldset and for every cours should be a input[type=checkbox](Or MultiCheckbox) Field generated
Sorry, I updated my question, because our designer send a wrong Image

I would no recommend create a separate field for every option.
You can define a list field in your z3c.form with the CheckBoxFieldWidget:
from zope import schema
from plone.directives import form
from z3c.form.browser.checkbox import CheckBoxFieldWidget
class IChannels(form.Schema)
form.widget(channels=CheckBoxFieldWidget)
channels = schema.List(
title=_(u'label_channels', default='Channels'),
value_type=schema.Choice(
vocabulary=u'channels.vocabulary'),
required=False)
Now register a vobaulary, name channels.vocabulary, which returns terms based on a catalog query.
from zope.interface import directlyProvides
from zope.schema import vocabulary
from zope.schema.interfaces import IVocabularyFactory
def channels_vocabulary(context):
catalog = getToolByName(context, 'portal_catalog')
terms = []
query = {} # Your query
for term in catalog(**query):
terms.append(vocabulary.SimpleTerm(value=term.decode('utf8'),
token=normalizer.normalize(term.decode('utf8')),
title=term.decode('utf8')))
return vocabulary.SimpleVocabulary(terms)
directlyProvides(channels_vocabulary, IVocabularyFactory)
Register with zcml:
<utility
component=".vocabularies.channels_vocabulary"
name="channels.vocabulary"
/>
The example is based on http://docs.plone.org/develop/plone/forms/schemas.html#multi-choice-example

Related

Tortoise pydantic_model_creator method not contain ForeignKeyField of a model

I have two models Article and Tag. Article has a foreign key from Tag
class Tag(MyAbstractBaseModel):
name = fields.CharField(max_length=255, index=True)
class Article(MyAbstractBaseModel):
title = fields.CharField(max_length=255, index=True)
body = fields.CharField(max_length=255)
tag = fields.ForeignKeyField(model_name="Tag", related_name='article', on_delete=fields.CASCADE)
Here I would like to have my response checked by the following
#router.get("/article", response_model=get_serialize_pydantic(Article))
async def get():
pass
Here is how I get the response model
from tortoise.contrib.pydantic import pydantic_model_creator
from pydantic import BaseModel, Field, create_model
def get_serialize_pydantic(models_obj: Type[Model], exclude: Tuple[str, ...] = None):
my_model_pydantic = pydantic_model_creator(models_obj)
response_pydantic = create_model(
__model_name=f"{models_obj.__name__}_response_pydantic",
data=(Optional[List[my_model_pydantic]], Field(None, title="data")),
__base__=BaseResponse)
return response_pydantic
Problem is I only title and body in my response model, there is no tag in it. Anyone knows why?
This is not an issue from pydantic side. It's pydantic_model_creator of tortoise that causes the problem.
The solution is simple. Just init before serialisation.
from tortoise import Tortoise
Tortoise.init_models(["__main__"], "models")
my_model_pydantic = pydantic_model_creator(models_obj)
https://tortoise-orm.readthedocs.io/en/latest/contrib/pydantic.html#relations-early-init

Saving object creation datetime using Pynamodb

I want to update the creation_datetime only when a new object is created and update the last_update_datetime on every update while using the save method. default_for_new is updating time even when the existing object is updating. any alternatives?
below is the sample code I tried
from pynamodb.models import Model
from pynamodb.attributes import UTCDateTimeAttribute
def current_datetime():
from datetime import datetime
return datetime.now()
class AbstractDateTimeModel(Model):
creation_datetime = UTCDateTimeAttribute(default_for_new=current_datetime)
last_update_datetime = UTCDateTimeAttribute(default=current_datetime)
class Meta(object):
abstract = True
The best way you can do this is overriding the update method of your Object class. This is an example:
from datetime import datetime, timezone
from pynamodb.models import Model
from pynamodb.settings import OperationSettings
from pynamodb.attributes import UTCDateTimeAttribute, UnicodeAttribute, NumberAttribute
def get_current_time_utc():
return datetime.now(timezone.utc)
class SalesItem(Model):
class Meta:
table_name = 'monthlySales'
id = UnicodeAttribute(hash_key=True)
month= UnicodeAttribute()
sales= NumberAttribute()
createDateTime = UTCDateTimeAttribute(default_for_new=get_current_time_utc)
updateDateTime = UTCDateTimeAttribute(default_for_new=get_current_time_utc)
# overriding the method to add timestamp on update
def update(self, actions=[], condition=None, settings=OperationSettings.default):
actions.append(SalesItem.updateDateTime.set(get_current_time_utc()))
Model.update(self, actions, condition, settings)
We just need to append an action to the actions list asking the timestamp update. Then call the parent's update method. Now you can forget about the timestamps and use the update method as you would.
item = SalesItem.get('pynamodb-test')
# do your updates here
item.update(actions=[
SalesItem.sales.set(item.sales + 1)
])

Mypy import not typing correctly

I have a type, Flag, in stubs/my_types/__init__.py
__all__ = ["Flag"]
Flag = TypedDict(
'Flag', {
'id': int
})
In my main source program, I import this with
from stubs.my_types import Flag
have a function I have annotated with
def do_stuff(thing: int) -> List[Flag]:
I've set the MYPYPATH to where the main source program is, but VsCode still shows the Flag as type Any. How can I get it to show the correct type?

Python - BaseHTTPServer , issue with POST and GET

I am making a very simple application with 2 webpages at the moment under URLs: localhost:8080/restaurants/ and localhost:8080/restaurants/new.
I have a sqlite database which i manipulate with SQLAlchemy in my python code.
On my first page localhost:8080/restaurants/, this just contains the lists of restaurants available in my database.
My second page localhost:8080/restaurants/new, is where i have a form in order to a new restaurant such that it displays on localhost:8080/restaurants.
However Whenever i enter a new restaurant name on form at localhost:8080/restaurants/new, it fails to redirect me back to localhost:8080/restaurants/ in order to show me the new restaurant, instead it just remains on the same url link localhost:8080/restaurants/new with the message "No data received" .
Below is my code:
import cgi
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
#import libraries and modules
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from database_setup import Base, Restaurant, MenuItem
#create and connect to database
engine = create_engine('sqlite:///restaurantmenu.db')
Base.metadata.bind=engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
class webServerHandler(BaseHTTPRequestHandler):
""" class defined in the main method"""
def do_GET(self):
try:
#look for url then ends with '/hello'
if self.path.endswith("/restaurants"):
self.send_response(200)
#indicate reply in form of html to the client
self.send_header('Content-type', 'text/html')
#indicates end of https headers in the response
self.end_headers()
#obtain all restaurant names from databse
restaurants = session.query(Restaurant).all()
output = ""
output += "<html><body><a href='/restaurants/new'>Add A New Restaurant</a>"
output += "</br></br>"
for restaurant in restaurants:
output += restaurant.name
output += """<div>
<a href='#'>Edit</a>
<a href='#'>Delete</a>
</div>"""
output += "</br></br>"
output += "</body></html>"
self.wfile.write(output)
print output
return
if self.path.endswith("/restaurants/new"):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
output = ""
output += "<html><body>"
output += "<h1>Add New Restaurant</h1>"
output += "<form method='POST' enctype='multipart/form-data action='/restaurants/new'>"
output += "<input name='newRestaurant' type='text' placeholder='New Restaurant Name'>"
output += "<input name='Create' type='submit' label='Create'>"
output += "</form></body></html>"
self.wfile.write(output)
return
except IOError:
self.send_error(404, "File %s not found" % self.path)
def do_POST(self):
try:
if self.path.endswith("/restaurants/new"):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
#check of content-type is form
if ctype == 'mulitpart/form-data':
#collect all fields from form, fields is a dictionary
fields = cgi.parse_multipart(self.rfile, pdict)
#extract the name of the restaurant from the form
messagecontent = fields.get('newRestaurant')
#create the new object
newRestaurantName = Restaurant(name = messagecontent[0])
session.add(newRestaurantName)
session.commit()
self.send_response(301)
self.send_header('Content-type', 'text/html')
self.send_header('Location','/restaurants')
self.end_headers()
except:
pass
def main():
"""An instance of HTTPServer is created in the main method
HTTPServer is built off of a TCP server indicating the
transmission protocol
"""
try:
port = 8080
#server address is tuple & contains host and port number
#host is an empty string in this case
server = HTTPServer(('', port), webServerHandler)
print "Web server running on port %s" % port
#keep server continually listening until interrupt occurs
server.serve_forever()
except KeyboardInterrupt:
print "^C entered, stopping web server...."
#shut down server
server.socket.close()
#run main method
if __name__ == '__main__':
main()
for reference here is my database_setup file where i create the database:
import sys
#importing classes from sqlalchemy module
from sqlalchemy import Column, ForeignKey, Integer, String
#delcaritive_base , used in the configuration
# and class code, used when writing mapper
from sqlalchemy.ext.declarative import declarative_base
#relationship in order to create foreign key relationship
#used when writing the mapper
from sqlalchemy.orm import relationship
#create_engine to used in the configuration code at the
#end of the file
from sqlalchemy import create_engine
#this object will help set up when writing the class code
Base = declarative_base()
class Restaurant(Base):
"""
class Restaurant corresponds to restaurant table
in the database to be created.
table representation for restaurant which
is in the database
"""
__tablename__ = 'restaurant'
#column definitions for the restaurant table
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
class MenuItem(Base):
"""
class MenuItem corresponds to restaurant table
table representation for menu_item which
is in the database
"""
__tablename__ = 'menu_item'
#column definitions for the restaurant table
name = Column(String(80), nullable=False)
id = Column(Integer, primary_key=True)
course = Column(String(250))
description = Column(String(250))
price = Column(String(8))
restaurant_id = Column(Integer, ForeignKey('restaurant.id'))
restaurant = relationship(Restaurant)
#create an instance of create_engine class
#and point to the database to be used
engine = create_engine(
'sqlite:///restaurantmenu.db')
#that will soon be added into the database. makes
#the engine
Base.metadata.create_all(engine)
I can't figure out why i cannot add new restuarants
I know this was a long time ago, but I figured out your problem.
First, the enctype='multipart/form-data' in your do_GET function under the if self.path.endswith("/restaurants/new"): portion is missing a final single quote. Second, you misspelt 'multipart' in if ctype == 'multipart/form-data':. Hope that can help you or others.
As shteeven said, the problem was with the encryption type in the form.
As the quote was missed, the 'Content-type' changed to 'application/x-www-form-urlencoded' so in that case you should parse it different as it's a string.
In order to manage both enctype you can modify your do_POST as the following
def do_POST(self):
try:
if self.path.endswith("/restaurants/new"):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
print ctype
#check of content-type is form
if (ctype == 'multipart/form-data') or (ctype == 'application/x-www-form-urlencoded'):
#collect all fields from form, fields is a dictionary
if ctype == 'multipart/form-data':
fields = cgi.parse_multipart(self.rfile, pdict)
else:
content_length = self.headers.getheaders('Content-length')
length = int(content_length[0])
body = self.rfile.read(length)
fields = urlparse.parse_qs(body)
#extract the name of the restaurant from the form
messagecontent = fields.get('newRestaurant')
#create the new object
newRestaurantName = Restaurant(name = messagecontent[0])
session.add(newRestaurantName)
session.commit()
self.send_response(301)
self.send_header('Location','/restaurants')
self.end_headers()
return
Hope this extra information is useful for you!

Plone 4 related items back reference issue

I failed to find back reference object for related items.
my code:
back_rels = list(catalog.findRelations({'to_id': intids.getId(aq_base(self.context))}))
for rel in back_rels:
ob = portal.unrestrictedTraverse(rel.from_path)
It throws exception when running at ob = portal.unrestrictedTraverse(rel.from_path).
Debug results:
> len(back_rels)
> 1
> rel
> <z3c.relationfield.relation.RelationValue object at oxoA86f8f0>
> rel.from_path
> 'new-grants-target-bioterrorism'
> rel.to_path
> '/portal/urnews/ur-gets-20-million-for-biodefense-studies'
I guess the problem is the rel.from_path doesn't return the full path like the rel.to_path does.
My question is how can rel.from_path return with full path and get right object at
portal.unrestrictedTraverse(rel.from_path)?
I am running Plone 4 and use dexterity content type.
Unfortunately you can't access from_object directy. It is explained in this issue http://code.google.com/p/dexterity/issues/detail?id=95
Use from_id, which stores IntId and use IntIds utility to retrieve the particular object:
from Acquisition import aq_inner
from zope.component import getUtility
from zope.intid.interfaces import IIntIds
from zope.security import checkPermission
from zc.relation.interfaces import ICatalog
def back_references(source_object, attribute_name):
""" Return back references from source object on specified attribute_name """
catalog = getUtility(ICatalog)
intids = getUtility(IIntIds)
result = []
for rel in catalog.findRelations(
dict(to_id=intids.getId(aq_inner(source_object)),
from_attribute=attribute_name)
):
obj = intids.queryObject(rel.from_id)
if obj is not None and checkPermission('zope2.View', obj):
result.append(obj)
return result

Resources