ValidationError when using pydantic Field - fastapi

I run these codes by defining two classes, Blackboard and Table, based on BaseModel. The I defined another class which takes two attributes: bloackboard, defined to be a Blackboard; tables, defined to be a list of Table class objects.
from typing import List
from pydantic import BaseModel, Field
class Blackboard(BaseModel):
size = 4000
color: str = Field(..., alias='yanse',
description='the color of the blackboard, you can choose green or black.')
class Table(BaseModel):
position: str
class ClassRoom(BaseModel):
blackboard: Blackboard
tables: List[Table]
m = ClassRoom(
blackboard={'color': 'green'},
tables=[{'position': 'first row, left 1'}, {'position': 'first row, left 2'}]
)
I got an error :
File "pydantic\main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for ClassRoom
blackboard -> yanse
field required (type=value_error.missing)
I want to know how could I correctly use Field class.
Thanks
I expect to have no error.

You are using an alias for the color field in your schema and filling your data with python dictionaries.
in this case, you should replace:
blackboard={'color': 'green'}
with:
blackboard={'yanse': 'green'}
The color field is used when you have a python schema object, not in dictionaries.

In case you wanted to populate your Blackboard model using color, you can activate allow_population_by_field_name option in the Blackboard config options as follow:
class Blackboard(BaseModel):
size = 4000
color: str = Field(..., alias='yanse',
description='the color of the blackboard,
you can choose green or black.')
class Config:
allow_population_by_field_name = True

Related

Dataclass attributes with init=False do not show in vars

I'm running Python 3.8.10 and have a dataclass with some attributes. Some of them have a default value but are not part of the constructor.
Attributes which have the init value set to False are not showing up in the object dict.
Is this the expected behavior? How can I force these attributes to show up in vars?
from dataclasses import dataclass, field
#dataclass
class Book:
name: str = field(default="", init=False)
author: str = field(default="", init=True)
b = Book()
b
> Book(name='', author='')
b.name
> ''
b.author
> ''
## name does not show up here
vars(b)
> {'author': ''}
b.__dict__
> {'author': ''}
I just hit the same issue. Some experimenting showed me that these variables show up in vars after they have been set.
I added the following to my __post_init__() and then they showed up in vars
def __post_init__(self):
for field in dataclasses.fields(self):
#Ensure that all dataclass fields show up in vars
if field.name not in vars(self):
setattr(self, field.name, getattr(self, field.name))
The docs also mention some other weirdness with using init=False. https://docs.python.org/3/library/dataclasses.html#dataclasses.replace
Be forewarned about how init=False fields work during a call to
replace(). They are not copied from the source object, but rather are
initialized in post_init(), if they’re initialized at all. It is
expected that init=False fields will be rarely and judiciously used.
Definitely check your assumptions when it comes to this feature I think.

WTForms-flask: organize formfield name and data into dictionary

I've been stuck on this for some time now:
I have a form like so:
class attributes(Form):
height=IntegerField('height')
weight=IntegerField('weight')
class main(Form):
John=FormField(attributes)
Ted=FormField(attributes)
David(FormField(attributes)`
I wish to iteratively create a dictionary to store an identifying field label and field data in flask without using John_height=John.height.data for every FormField. The idea is to eventually pass the dictionary for writing into a database using a SQL statement where the dictionary key will match the database column and formfield data will be the database values.
The dictionary should look something like this:
{John_height : 170,
John_weight: 170,
Ted_height : 120,
Ted_weight: 190,
David_height : 150,
David_weight: 100}
Thank you in advance.
from wtforms import Form
from wtforms.fields import IntegerField, FormField
class Attributes(Form):
height = IntegerField('height')
weight = IntegerField('weight')
To build your forms iteratively you can do either of these:
def main(people=['John', 'Ted', 'David']):
class Main(Form):
pass
for person in people:
setattr(Main, person, FormField(Attributes))
return Main()
or
class Main(Form):
for person in ['John', 'Ted', 'David']:
vars()[person] = FormField(Attributes)
del person
personally I prefer the second since it is a proper class structure but less dynamic.
To build your dictionary you can then do the following:
obj = Main()
data = dict()
for field in obj: # <- this works since obj has an __iter__ method self defined
for key in field.data.keys():
data.update({field.name + '_' + key: field.data[key]})
print(data)
>>> {'John_height': None, 'John_weight': None, 'Ted_height': None, 'Ted_weight': None, 'David_height': None, 'David_weight': None}
The None values are due to empty form construction.

How to set default css classes for all built-in form widgets in Django

Short version: is it possible to define a set of default css classes that Django should use whenever rendering a form ?
Long version:
The context is as follows: I would like to use the css classes defined in the w3.css framework for all my forms (http://www.w3schools.com/w3css/default.asp). I have seen that it is possible to do that in Django at form class definition or at form rendering, but it requires in both cases an explicit declaration of all the form fields. That means that I loose all the benefit of automatic form generation for ModelForms. I would like something as follows instead:
Define somewhere (e.g. in the settings file) a default mapping between form fields / widgets and css classes, e.g. 'textinput': 'my_default_css_class_for_text_inputs'
By default, for all automatic generation and rendering of forms, the default css classes defined in (1) are used, with no or minimal modification of the existing form classes
For specific forms, I can overload the defaults with other values
As far as I've understood, such behaviour is not possible in django. The crispy-forms package seems to go in that direction, but it seems to do much more than just that, and I am not sure that I want all the extra complexity (I'm still a newbie around here). An alternative would be to use javascript to add the classes on the client side. It looks like an ugly bad practice to me.
Could anyone confirm my understanding of this issue and point me towards elegant solutions, if any ?
Thanks !
Jonathan
I've managed to find the answer to my question and I'm posting it here for posterity. For the label class, I had some inspiration from here and here (answer from user2732686). The first link suggests to redefine the label_tag method of the BoundField class at run-time. It's a less verbose solution than the one suggested in the 2nd link, but at the cost of a project-wide hack, which I would not recommend. Here, I follow Django's subclassing mania, as suggested in the 2nd link for the labels.
In the projects settings.py, add:
# Default css classes for widgets and labels
DEFAULT_CSS = {
'error': 'w3-panel w3-red', # displayed in the label
'errorlist': 'w3-padding-8 w3-red', # encloses the error list
'required': 'w3-text-indigo', # used in the label and label + input enclosing box. NB: w3-validate only works if the input precedes the label!
'label': 'w3-label',
'Textarea': 'w3-input w3-border',
'TextInput': 'w3-input w3-border',
'Select': 'w3-select w3-border',
}
NB: apart from the 4 first keys, the keys must match Django's widget names.
In your forms.py (or elsewhere), add:
from django.forms import ModelForm, inlineformset_factory, Form, BoundField
from django.forms.utils import ErrorList
from django.utils.html import format_html, force_text
from django.conf import settings
class CustErrorList(ErrorList):
# custom error list format to use defcss
def __str__(self):
return self.as_div()
def as_div(self):
if not self:
return ''
return format_html('<div class="{}">{}</div>',
settings.DEFAULT_CSS['errorlist'],
' '.join( [ force_text(e) for e in self ] )
)
class CustBoundField(BoundField):
# overload label_tag to include default css classes for labels
def label_tag(self, contents=None, attrs=None, label_suffix=None):
newcssclass = settings.DEFAULT_CSS['label']
if attrs is None:
attrs = {}
elif 'class' in attrs:
newcssclass = ' '.join( [ attrs['class'], newcssclass ] ) # NB: order has no impact here (but it does in the style sheet)
attrs.update( { 'class': newcssclass } )
# return the output of the original method with the modified attrs
return super( CustBoundField, self ).label_tag( contents, attrs, label_suffix )
def custinit(self, subclass, *args, **kwargs):
# overload Form or ModelForm inits, to use default CSS classes for widgets
super( subclass, self ).__init__(*args, **kwargs)
self.error_class = CustErrorList # change the default error class
# Loop on fields and add css classes
# Warning: must loop on fields, not on boundfields, otherwise inline_formsets break
for field in self.fields.values():
thiswidget = field.widget
if thiswidget .is_hidden:
continue
newcssclass = settings.DEFAULT_CSS[ thiswidget.__class__.__name__ ]
thisattrs = thiswidget.attrs
if 'class' in thisattrs:
newcssclass = ' '.join( [ thisattrs['class'], newcssclass ] ) # NB: order has no impact here (but it does in the style sheet)
thisattrs.update( { 'class': newcssclass } )
def custgetitem(self, name):
# Overload of Form getitem to use the custom BoundField with
# css-classed labels. Everything here is just a copy of django's version,
# apart from the call to CustBoundField
try:
field = self.fields[name]
except KeyError:
raise KeyError(
"Key '%s' not found in '%s'. Choices are: %s." % (
name,
self.__class__.__name__,
', '.join(sorted(f for f in self.fields)),
)
)
if name not in self._bound_fields_cache:
self._bound_fields_cache[name] = CustBoundField( self, field, name )
# In the original version, field.get_bound_field is called, but
# this method only calls BoundField. It is much easier to
# subclass BoundField and call it directly here
return self._bound_fields_cache[name]
class DefaultCssModelForm(ModelForm):
# Defines the new reference ModelForm, with default css classes
error_css_class = settings.DEFAULT_CSS['error']
required_css_class = settings.DEFAULT_CSS['required']
def __init__(self, *args, **kwargs):
custinit(self, DefaultCssModelForm, *args, **kwargs)
def __getitem__(self, name):
return custgetitem(self, name)
class DefaultCssForm(Form):
# Defines the new reference Form, with default css classes
error_css_class = settings.DEFAULT_CSS['error']
required_css_class = settings.DEFAULT_CSS['required']
def __init__(self, *args, **kwargs):
custinit(self, DefaultCssForm, *args, **kwargs)
def __getitem__(self, name):
return custgetitem(self, name)
NB: replace <MY_PROJECT> with your project name
Then, you simply subclass DefaultCssModelForm and DefaultCssForm instead of ModelForm and Form when defining your forms. For formsets, use these classes as base classes. To illustrate:
class MyForm(DefaultCssModelForm):
class Meta:
model = MyModel
fields = '__all__'
MyFormSet = inlineformset_factory( ..., ..., form=DefaultCssModelForm, ... )

How I can color words inside array in codemirror in diffrente color?

I have array of word build dynamic on event cursoractivity ,
what I do is :
I build my own language from metadata store in xml file so when I type on codemirror :
car.whell.circle.number employee.getname()
I store all the words in array like this :
so I store every word with it's type ,
Note :
if I have tow class :
The name of first class is Data and it's fields are:
fname, lname, age
The name of second class is info and its fields are:
mother, father
To color the fields in specific color only if it comes after the name of own class (i.e when I type on codemirror Data.fname I want to color the word fname in green color But when I type on codemirror info.fname I did not want to color the word fname in green color because (fname not contain in the class "info")) so I build dynamic array store the words after i check if I can color it ,so every word in dynamic array I can color it, the useful of my dynamic array to knew if I can color the word or I can not .
what I want to do :
I want to color every word it's type : class by red color, and the the word it's type classsomthing by blue color, and the word it's type (primitive like int,string) by green color , so any body can help me How I can color the words in my dynamic array only if it come in the specific order in my dynamic array and with color define by type stored in my dynamic array??
Thanks in advance

Plone and Dexterity: default values for "relation" field

In one of my Plone sites, I have a few dexterity models that I use to generate letters. The models are: "Model" (the base content of the letter), "Contact" (that contains the contact information, such as name, address etc) and "Merge" (which is a Model object rendered, in which we substitute some parts of the model with the recipients information).
The schema of the "Merge" object is the following:
class IMergeSchema(form.Schema):
"""
"""
title = schema.TextLine(
title=_p(u"Title"),
)
form.widget(text='plone.app.z3cform.wysiwyg.WysiwygFieldWidget')
text = schema.Text(
title=_p(u"Text"),
required=False,
)
form.widget(recipients=MultiContentTreeFieldWidget)
recipients = schema.List(
title=_('label_recipients',
default='Recipients'),
value_type=schema.Choice(
title=_('label_recipients',
default='Recipients'),
# Note that when you change the source, a plone.reload is
# not enough, as the source gets initialized on startup.
source=UUIDSourceBinder(portal_type='Contact')),
)
form.widget(model=ContentTreeFieldWidget)
form.mode(model='display')
model = schema.Choice(
title=_('label_model',
default='Model'),
source=UUIDSourceBinder(portal_type='Model'),
)
When creating a new "Merge" object, I want to have the "recipients" fields be preset with all contacts available in the folder where the new object is created.
I followed Martin Aspelli's guide to add a default value for a field: http://plone.org/products/dexterity/documentation/manual/developer-manual/reference/default-value-validator-adaptors
It works fine for text input fields, but I can't have it working for the "recipients" field. The method to generate the default values is the following (with some debug info with ugly print, but they'll be removed later ;) ):
#form.default_value(field=IMergeSchema['recipients'])
def all_recipients(data):
contacts = [x for x in data.context.contentValues()
if IContact.providedBy(x)]
paths = [u'/'.join(c.getPhysicalPath()) for c in contacts]
uids = [IUUID(c, None) for c in contacts]
print 'Contacts: %s' % contacts
print 'Paths: %s' % paths
print 'UIDs: %s' % uids
return paths
I tried to return the objects directly, their relative path (in the add view, when accessing "self.widgets['recipients'].value", I get this type of data) their UIDs but none of the solution as any effect.
I also tried to return tuples instead of lists or even generators, but still no effect at all.
The method is called for sure, as I see traces in the instance log.
I think you need to get the "int_id" of the related content. That's how dexterity relation fields store relation info::
from zope.component import getUtility
from zope.intid.interfaces import IIntIds
#form.default_value(field=IMergeSchema['recipients'])
def all_recipients(data):
contacts = [x for x in data.context.contentValues()
if IContact.providedBy(x)]
intids = getUtility(IIntIds)
# The following gets the int_id of the object and turns it into
# RelationValue
values = [RelationValue(intids.getId(c)) for c in contacts]
print 'Contacts: %s' % contacts
print 'Values: %s' % values
return values

Resources