I am trying to filter a null field and validate it in forms.py But i get below error :
Cannot assign None: "TeacherAttendance.teacher" does not allow null values.
But i am doing validation in the form as below for teacher field. It should generate "Please choose teacher" validation warning. But it is not doing.
It should validate the null value for teacher and go back to form with a validation warning if i dont choose a teacher from teacher field.
class TeacherAttendanceForm(forms.ModelForm):
class Meta:
model = TeacherAttendance
fields = ('time', 'attendance', 'teacher','dailynote','writer',)
exclude = ['uuid', 'notedate',]
widgets = {
'attendance': forms.RadioSelect(renderer=HorizontalRadioRenderer),
'dailynote': forms.Textarea(attrs={'rows': 10}),
'writer': forms.Textarea(attrs={'rows': 1}),
'uuid': forms.HiddenInput(),
'semester': forms.HiddenInput(),
}
def clean(self):
if str(self.cleaned_data['time']) == "-----------":
raise forms.ValidationError('Please choose time.')
if self.cleaned_data['dailynote'] == "":
raise forms.ValidationError('Please enter note.')
if not self.cleaned_data['teacher']:
raise forms.ValidationError('Please choose teacher .')
My model is below and teacher field is a dropdown filed that shows all teacher.
class TeacherAttendance(BaseModel):
teacher = models.ForeignKey(Staff, blank=True, verbose_name=_("Choose Teacher"))
attendance = models.CharField(choices=TEACHER_ATTENDANCE, default="YOK", max_length=20, verbose_name=_("Attendance"))
time = models.CharField(choices=TIME, default="-------------", max_length=20, verbose_name=_("Time"))
dailynote = models.TextField(null=True, blank=True, verbose_name=_("Add Note"))
notedate = models.DateField(auto_now_add=True, db_index=True, verbose_name=_("Date"))
writer = models.TextField(null=True, blank=True, verbose_name=_("Writer"))
class Meta:
unique_together = ("teacher", "attendance", "notedate")
index_together = [["teacher", "notedate", ], ]
def __unicode__(self):
return "%s / %s / %d " % (self.teacher, self.notedate, self.attendance)
I solved the question by changing below field in model :
teacher = models.ForeignKey(Staff, blank=True, verbose_name=_("Choose Teacher"))
to :
teacher = models.ForeignKey(Staff, blank=True, null=True, verbose_name=_("Choose Teacher"))
by adding "null=True" to the field. Probably it was first looking at the model field before doing form validation.
Related
I have a model:
class Contact(db.Model):
__tablename__ = 'contact'
contactid = db.Column(db.BigInteger, primary_key=True, server_default=db.text("nextval('contact_contactid_seq'::regclass)"))
firstname = db.Column(db.Text)
lastname = db.Column(db.Text)
and a form
class ContactForm(FlaskForm):
contactid = HiddenField('contactid')
firstname = StringField('First Name', validators=[Optional()], filters = [lambda x: x or None])
lastname = StringField('Last Name', validators=[Optional()], filters = [lambda x: x or None])
submit = SubmitField('Save')
I use code similar to the following to insert and update records in the database using the above model and form
#blueprint.route('/create', methods=['GET', 'POST'])
def create():
form = ContactForm()
if form.validate_on_submit():
r = Contact()
form.populate_obj(r)
db.session.add(r)
db.session.commit()
flash("saved new record", "success")
return root()
return render_template('contact/create.html', form=form)
#blueprint.route('/edit/<id>', methods=['GET', 'POST'])
def edit(id: int):
r = Contact.query.get_or_404(id)
form = ContactForm(obj=r)
if form.validate_on_submit():
form.populate_obj(r)
db.session.commit()
flash("updated record", "success")
return redirect(url_for('blueprint.root'))
return render_template('contact/edit.html', form=form)
The Problem
SQLAlchemy appears to be generating SQL like this:
INSERT INTO contact (contactid, firstname, lastname) VALUES (%(contactid)s, %(firstname)s, %(lastname)s)
UPDATE contact set contactid=%(contactid)s, firstname=%(firstname)s, lastname=%(lastname)s WHERE contactid = %(contactid)s
I want it to do it like this:
INSERT INTO contact (firstname, lastname) VALUES (%(firstname)s, %(lastname)s)
SELECT last_contactid_somehow
UPDATE contact set firstname=%(firstname)s, lastname=%(lastname)s WHERE contactid = %(contactid)s
What am I doing wrong?
I would like a solution where SqlAlchemy:
handles the auto-incrementing primary key without sticking it into the insert statement
doesn't set the primary key in the update statement
I am using Postgres
I think the first problem will be solved by setting autoincrement=True
class Contact(db.Model):
__tablename__ = 'contact'
contactid = db.Column(db.BigInteger, primary_key=True, autoincrement=True, server_default=db.text("nextval('contact_contactid_seq'::regclass)"))
...
the second problem is actually working properly because you defined the form class like that.
In addition, the query you want and the query generated by SQLAlchemy are the same because the contractid in the where clause and the contractid in the set clause is same.
Nevertheless, if you want to change the query, change the value of the model object.
r = Contact.query.get_or_404(id)
form = ContactForm(obj=r)
if form.validate_on_submit():
r.firstname = form.firstname.data
r.lastname = form.lastname.data
db.session.commit()
...
While customer creation , i need to store dob attribute for customer.which is not saving. facing issue like,
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'customer_entity.value_id' in 'field list', query was: SELECT customer_entity.value_id FROM customer_entity WHERE (attribute_id='11' AND entity_id='199')
meanwhile,if i added custom date attribute in customer entity it get saved.
Any one have any idea about it.
Thanks in advance.
I am storing custom attributes as given below,
$data = []; //Array of attributes with key as attribute code
$customer = $this->customerModel->load($customerId);
$customerData = $customer->getDataModel();
$customerResource = $this->customerAttrFactory->create();
foreach ($data as $attrCode => $attrValue):
$customerData->setCustomAttribute($attrCode, $attrValue);
$customer->updateData($customerData);
$customerResource->saveAttribute($customer, $attrCode);
endforeach;
No need to save dob as an attribute.
Customer entity table has dob field so we can set it through customer model as given below.
$websiteId = $this->storeManager->getWebsite()->getWebsiteId();
$customer = $this->customerFactory->create();
$customer->setWebsiteId($websiteId);
$data['dob'] = $formData['dob'];
$customer->setData($data);
$customer->save();
This part of the app works, buts it's ugly and not sustainable. Need a more evolved solution.
PROBLEM I AM TRYING TO SOLVE:
This part of the application enables users to access a form to enter purchases they've made and store them in a Postgres DB. I am using Flask SQLAlchemy ORM.
Within my purchase table exists a field store_id, that has a ForeignKey relationship to my store table. I don't want my user to select a store ID # in the form, so I am using a SelectField to enable them to choose the store name instead. However, I can't seem to find a sustainable way to translate the store name back to its associated ID. Right now I am using the ugly IF statements seen below.
What is a better way to map/translate store name to ID which is already housed in the "store" table in my DB?
MY MODEL:
class Purchase(db.Model):
id = db.Column(db.Integer, primary_key=True)
item = db.Column(db.String(80))
quantity = db.Column(db.Integer)
unit_cost = db.Column(db.Integer)
total_cost= db.Column(db.Integer)
date = db.Column(db.DateTime)
store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
MY FORM:
class CreatePurchase(FlaskForm):
item = StringField('Item', validators=[DataRequired()])
quantity = IntegerField('Quantity', validators=[DataRequired()])
unit_cost = IntegerField('Unit Cost', validators=[DataRequired()])
total_cost = IntegerField('Total Cost', validators=[DataRequired()])
store_id = SelectField("Store Selector", choices=[('0','Select Store'),('1','Furgesons'), ('2','Ocean State'), ('3','Chewy'), ('4','Amazon'), ('5', 'Rumford')])
date = DateField('Purchase Date', validators=[DataRequired()])
submit = SubmitField('Enter')
MY ROUTE:
#main.route('/enter_purchases', methods=['GET', 'POST'])
def enter_purchase():
form = CreatePurchase()
x = str(form.store_id) # this is a store name from our form
p = 0
if "Ocean State" in x:
p = 2
elif "Amazon" in x:
p = 4
elif "Furgesons" in x:
p = 1
elif "Chewy" in x:
p = 3
elif "Rumford" in x:
p = 5
if form.validate_on_submit():
purchase = Purchase(item=form.item.data, quantity=form.quantity.data, unit_cost=form.unit_cost.data,
total_cost=form.total_cost.data, date=form.date.data,store_id=p)
db.session.add(purchase)
db.session.commit()
flash('New purchase added successfully')
return redirect(url_for('main.success'))
return render_template('enter_purchases.html', form=form)
You have a store table, with a numeric id (as the PK) and a name attribute:
class Store(db.Model):
store_id = ..
store_name = ..
You populate your form with all of the unique values from the store_name. This needs to be a dynamically generated form, so instead of using a form that is statically created do something like:
def CreatePurchase()
class TempForm(FlaskForm):
item = StringField('Item', validators=[DataRequired()])
quantity = IntegerField('Quantity', validators=[DataRequired()])
unit_cost = IntegerField('Unit Cost', validators=[DataRequired()])
total_cost = IntegerField('Total Cost', validators=[DataRequired()])
date = DateField('Purchase Date', validators=[DataRequired()])
submit = SubmitField('Enter')
choices = ## some SQLalchemy code to get all unique store_names from the table
TempForm.store_id = SelectField("Store Selector", choices=choices)
return TempForm()
Then form.store_id will provide the right id, but display the string name of the store in the form.
The key in this setup is making sure you use the right SQLalchemy code to populate the SelectField dynamically. Basically for each store in the table you can just iterate through something like this:
choices = list()
for store in Store.query.all(): # <- assumes store_id and store_names are unique
choices.append((store.store_id, store.store_name))
In this function I'm not able to filter Categories alone. So please tell me how to do that? Here I used array model field for categories as well as specifications. From this array model field I could not get the categories column using query
set category_name=Product.objects.values_list('categories', flat=True).distinct()
And in that filter should be distinct values. So what query has to given for retrieving this categories values
models.py
class Product(models.Model):
name = models.CharField(max_length=255)
image = models.ImageField(upload_to = '',blank="True")
categories = models.ArrayModelField(
model_container=Categories,
model_form_class=CategoriesForm
)
specifications = models.ArrayModelField(
model_container=Specifications,
model_form_class=SpecificationsForm
)
description = models.TextField()
reviews = models.ArrayModelField(
model_container=Reviews,
model_form_class=ReviewsForm
)
drizzly = models.BooleanField()
complete = models.BooleanField()
def __str__(self):
return self.name
class Categories(models.Model):
name = models.CharField(max_length=255)
class Meta:
abstract = True
views.py
def index(request):
data = Product.objects.all()
category_name=Product.objects.values_list('categories', flat=True).distinct()
return render(request, 'db.html', data':data,'category_name':category_name})
I'm using django.contrib.auth.models.User model class with no custom code and i've the following model as well:
class XYZ(models.Model):
xyzstring = models.TextField()
created_by = models.ForeignKey(User)
The resource classes are as follows:
class UserResource(ModelResource):
class Meta:
queryset = User.objects.all()
resource_name = 'user'
excludes = ['email', 'password', 'is_active', 'is_staff', 'is_superuser']
filtering = {
'username': ALL,
}
class XYZResource(ModelResource):
created_by = fields.ForeignKey(UserResource, 'user', full=True)
class Meta:
queryset = XYZ.objects.all()
resource_name = 'xyz'
allowed_methods = ['get','post','put']
details_uri_name= 'id'
paginator_class = Paginator
When i go to /api/v1/xyz/ I get the error:
model 'XYZ' has an empty attribute 'user' and doesn't allow a null value.
The database has valid userids in the created_by column in the xyz table. IF i remove created_by line in the XYZResource, i dont get created_by attribute at all. created_by will not take null values as XYZ objects are created by valid users.
Please suggest what should i do to fix this problem
Guys thank you very much for trying to help me out. Out of frustration i replaced "user" in the following line with "created_by" and it WORKED!!
created_by = fields.ForeignKey(UserResource, 'user', full=True)
TO
created_by = fields.ForeignKey(UserResource, 'created_by', full=True)
Change the created_by field to allow a null value
created_by = fields.ForeignKey(UserResource, 'user', full=True, null=True)