Htmx Is working for evey Select field that is so configured in forms.py with render_kw and getting updated with form.populate_for_updating() or similar.

master
Kerem Yollu 10 months ago
parent 55b9210990
commit bf3fab9045

@ -0,0 +1 @@
,key,devbian,16.08.2024 16:53,file:///home/key/.config/libreoffice/4;

@ -1,2 +1,3 @@
name,device_id,serial_no,imsi,iccid,ip,port,device_user_id,device_owner_id,company_manufacturer_id,status_id,type_id,area_id,company_owner_id
miniUni,24070580,24070576,901405710203483,898822800001074,10.128.24.42,50000,1,1,1,1,1,1,3
name,model,device_id,serial_no,imsi,iccid,ip,port,device_user_id,device_owner_id,company_manufacturer_id,status_id,type_id,area_id,company_owner_id
miniUni,NB-MU-CON-IP65,24070580,24070576,901405710203483,89882280000107407542,10.128.24.42,50000,1,1,1,1,1,1,1
miniUni,NB-MU-CON-IP65,24070578,24070574,901405710203484,89882280000107407559,10.128.24.43,50000,1,1,1,1,1,1,1

1 name model device_id serial_no imsi iccid ip port device_user_id device_owner_id company_manufacturer_id status_id type_id area_id company_owner_id
2 miniUni NB-MU-CON-IP65 24070580 24070576 901405710203483 898822800001074 89882280000107407542 10.128.24.42 50000 1 1 1 1 1 1 3 1
3 miniUni NB-MU-CON-IP65 24070578 24070574 901405710203484 89882280000107407559 10.128.24.43 50000 1 1 1 1 1 1 1

@ -1,2 +1,4 @@
name,description
WaterDetector,Sensor for detection water levels.
Water,Sensor for detection water levels.
Humidity,Sensor for detection humidity levels.
Pressure,Sensor for detection pressure levels.

1 name description
2 WaterDetector Water Sensor for detection water levels.
3 Humidity Sensor for detection humidity levels.
4 Pressure Sensor for detection pressure levels.

Binary file not shown.

@ -24,6 +24,11 @@ mail = Mail() # So that we can send mails
# (SESSION) Starts the curren flask session
session = Session()
# Definition of custom filter for Jinja2
def get_attr(obj, attr):
print(obj)
print(attr)
return(getattr(obj, attr.strip(), None) )
def create_app():
# (APP) Definition
@ -51,6 +56,7 @@ def create_app():
from minibase.blueprints.company.routes import company
from minibase.blueprints.geography.routes import geography
from minibase.blueprints.sensor.routes import sensor
from minibase.blueprints.database.routes import database
# (BLUEPRINTS) Registering the blueprints.
# Giving them theie ulr_prefixes that will define their links on the webBrowser.
@ -60,6 +66,10 @@ def create_app():
app.register_blueprint(company, url_prefix='/company')
app.register_blueprint(geography, url_prefix='/geography')
app.register_blueprint(sensor, url_prefix='/sensor')
app.register_blueprint(database, url_prefix='/database')
# Addinf the custom get_attr() filter to Jinja2 template engine
app.add_template_filter(get_attr)
# (APP) Returning the initialised app
return app

@ -33,6 +33,8 @@ class companyForm(FlaskForm): # Defines the form class to be used for the user
submit = SubmitField()
def populate_for_updating(self, company):
self.originalModel = company
print(f"company.name={company.name}")
self.submit.label.text = "Update"
self.country_id.choices = [(row.id, row.name) for row in geoUtils.queryCountryNamesWithDefault(company.country_id)]
@ -51,10 +53,10 @@ class companyForm(FlaskForm): # Defines the form class to be used for the user
self.status_id.choices = [(row.id, row.name) for row in companyUtils.queryStatusNamesWithDefault(company.status_id)]
def populate_for_adding(self, company):
self.originalModel = company
self.submit.label.text = "Add"
del self.image_file
self.country_id.choices = [(row.id, row.name) for row in geoUtils.queryCountryNames()]
# This is for the htmx implementation. please be careful how of there is data we switch the funtion needed
@ -71,8 +73,9 @@ class companyForm(FlaskForm): # Defines the form class to be used for the user
self.relation_id.choices = [(row.id, row.name) for row in companyUtils.queryRelationNames()]
self.status_id.choices = [(row.id, row.name) for row in companyUtils.queryStatusNames()]
# Queries to be made in order to validate the form : If username exists
def validate_companyName(self, company_name):
company = companyUtils.queryByNameFirst(company_name)
if company:
raise ValidationError('That username is taken please choose another one')
#custom validators specific naming convention: validate_<fieldname>. This is how Flask-WTF knows which field the validator is associated with.
def validate_name(self, input):
if input.data != self.originalModel.name:
if (Companies.query.filter(Companies.name.ilike(f'%{input.data}%')).first()):
raise ValidationError('This Company already registered')

@ -0,0 +1,31 @@
from flask import render_template, Blueprint, request, flash, redirect, url_for, jsonify
from minibase.blueprints.company.models import Companies
database = Blueprint('database', __name__, template_folder='templates')
@database.route('/search/<field_name>/<table_name>/<key_name>/<ret_name>', methods=['GET'])
def search_auto(field_name, table_name, key_name, ret_name):
keyLike = request.args.get('modalReqArg', '')
MODEL_MAP = {
'Companies': Companies,
}
table = MODEL_MAP.get(table_name)
if table is None:
return f"Error: Table '{table_name}' not found.", 400
column = getattr(table, key_name.strip(), None)
if column is None:
return f"Error: Column '{key_name}' not found in table '{table_name}'.", 400
# Proceed with filtering if the column is found
results = table.query.filter(column.ilike(f'%{keyLike}%')).all()
return render_template('database/search_results.html', field_name=field_name, results=results, returnAttr=ret_name)
@database.route('/select/<field_name>/<int:result_id>/<result_content>', methods=['GET'])
def select_field(field_name, result_id, result_content):
return f'<option value="{result_id}" selected>{result_content}</option>'

@ -0,0 +1,12 @@
<ul class="list-group">
{% for result in results %}
<li class="list-group-item">
<a href="#" hx-get="/database/select/{{ field_name }}/{{ result.id }}/{{ result|get_attr(returnAttr) }}"
hx-target="#{{ field_name }}"
hx-trigger="click"
hx-swap="innerHTML"
data-bs-dismiss="modal"
class="text-decoration-none">{{ result.name }}</a>
</li>
{% endfor %}
</ul>

@ -10,6 +10,7 @@ from datetime import date
class nbiotDeviceForm(FlaskForm): # Defines the self class to be used for the user update
name = StringField('Device Name', validators=[DataRequired(), Length(min=3, max=50)])
model = StringField('Device Model', validators=[DataRequired(), Length(min=3, max=50)])
serial_no = StringField('Serial Number', validators=[DataRequired(), Length(min=3, max=50)])
device_id = StringField('Device Id', validators=[DataRequired(), Length(min=3, max=50)])
imsi = StringField('Imsi No', validators=[DataRequired(), Length(min=10, max=50)])
@ -19,71 +20,75 @@ class nbiotDeviceForm(FlaskForm): # Defines the self class to be used for the u
registration_date = DateField('Registration Date', format='%Y-%m-%d', default=date.today, validators=[DataRequired()])
activation_date = DateField('Activation Date', format='%Y-%m-%d', default=date.today, validators=[DataRequired()])
deactivation_date = DateField('Deactivation Date', format='%Y-%m-%d', default=date.today, validators=[DataRequired()])
owner_id = SelectField('Owner', validators=[DataRequired()])
user_id = SelectField('User')
device_owner_id = SelectField('Owner', validators=[DataRequired()])
device_user_id = SelectField('User')
status_id = SelectField('Status', validators=[DataRequired()])
type_id = SelectField('Type', validators=[DataRequired()])
area_id = SelectField('Area', validators=[DataRequired()])
manufacturer_id = SelectField('Manufacturer', validators=[DataRequired()],
render_kw={
'hx-target': '#manufacturer_id', # Target div or modal for the popup
'hx-swap': 'outerHTML' # Swap the outer HTML of the target element
company_manufacturer_id = SelectField( 'Manufacturer', validators=[DataRequired()],
render_kw={"custom_option": "search_field",
"query_table": "Companies",
"query_key": "name",
"query_return": "name"
})
company_owner_id = SelectField('Managed By', validators=[DataRequired()],
render_kw={"custom_option": "search_field",
"query_table": "Companies",
"query_key": "name",
"query_return": "name"
})
company_id = SelectField('Managed By', validators=[DataRequired()])
image_file = FileField('Update Sensor Picture', validators=[FileAllowed(['jpg', 'png'])])
submit = SubmitField()
def populate_for_updating(self, device):
self.originalModel = device
self.submit.label.text = "Update"
self.user_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_user_id)]
self.owner_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_owner_id)]
self.manufacturer_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_manufacturer_id)]
self.company_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_owner_id)]
self.device_user_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_user_id)]
self.device_owner_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_owner_id)]
self.company_manufacturer_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_manufacturer_id)]
self.company_owner_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_owner_id)]
self.status_id.choices = [(row.id, row.name) for row in sensorUtils.queryStatusNamesWithDefault(device.status_id)]
self.type_id.choices = [(row.id, row.name) for row in sensorUtils.queryTypeNamesWithDefault(device.type_id)]
self.area_id.choices = [(row.id, row.name) for row in sensorUtils.queryAreaNamesWithDefault(device.area_id)]
def populate_for_adding(self, device):
self.originalModel = device
self.submit.label.text = "Add"
if self.manufacturer_id.data:
self.manufacturer_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(self.manufacturer_id.data)]
if self.company_manufacturer_id.data:
self.company_manufacturer_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(self.company_manufacturer_id.data)]
self.user_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_user_id)]
self.owner_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_owner_id)]
self.manufacturer_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_manufacturer_id)]
self.company_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_owner_id)]
self.device_user_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_user_id)]
self.device_owner_id.choices = [(row.id, row.username) for row in userUtils.queryUserNamesWithDefault(device.device_owner_id)]
self.company_manufacturer_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_manufacturer_id)]
self.company_owner_id.choices = [(row.id, row.name) for row in companyUtils.queryNamesWithDefault(device.company_owner_id)]
self.status_id.choices = [(row.id, row.name) for row in sensorUtils.queryStatusNamesWithDefault(device.status_id)]
self.type_id.choices = [(row.id, row.name) for row in sensorUtils.queryTypeNamesWithDefault(device.type_id)]
self.area_id.choices = [(row.id, row.name) for row in sensorUtils.queryAreaNamesWithDefault(device.area_id)]
#custom validators specific naming convention: validate_<fieldname>. This is how Flask-WTF knows which field the validator is associated with.
def validate_name(self, input):
if input.data != self.name:
content = nbiotDevice.query.filter_by(name=input.data).first()
if content:
raise ValidationError('That device name is taken please choose another one')
if input.data != self.originalModel.name:
if (nbiotDevice.query.filter(nbiotDevice.name.ilike(f'%{input.data}%')).first()):
raise ValidationError('This Name already exists. Please choose a different one.')
def validate_device_id(self, input):
if input.data != self.device_id:
content = nbiotDevice.query.filter_by(device_id=input.data).first()
if content:
raise ValidationError('That device id is taken please choose another one')
def validate_serial_no(self, input):
if input.data != self.originalModel.serial_no:
if (nbiotDevice.query.filter(nbiotDevice.serial_no.ilike(f'%{input.data}%')).first()):
raise ValidationError('This Serial Number is already registered.')
def validate_imsi(self, input):
if input.data != self.imsi:
content = nbiotDevice.query.filter_by(imsi=input.data).first()
if content:
raise ValidationError('That IMSI id is taken please choose another one')
if input.data != self.originalModel.imsi:
if (nbiotDevice.query.filter(nbiotDevice.imsi.ilike(f'%{input.data}%')).first()):
raise ValidationError('This IMSI no is already registered.')
def validate_iccid(self, input):
if input.data != self.iccid:
content = nbiotDevice.query.filter_by(iccid=input.data).first()
if content:
raise ValidationError('That ICCID id is taken please choose another one')
if input.data != self.originalModel.iccid:
if (nbiotDevice.query.filter(nbiotDevice.iccid.ilike(f'%{input.data}%')).first()):
raise ValidationError('This ICCID no is already registered.')
def validate_ip(self, input):
if input.data != self.ip:
content = nbiotDevice.query.filter_by(ip=input.data).first()
if content:
raise ValidationError('That IP id is taken please choose another one')
if input.data != self.originalModel.ip:
if (nbiotDevice.query.filter(nbiotDevice.ip.ilike(f'%{input.data}%')).first()):
raise ValidationError('A devie already has this IP')

@ -6,6 +6,7 @@ class nbiotDevice(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
model = db.Column(db.String(50), nullable=False)
serial_no = db.Column(db.String(50), nullable=False)
device_id = db.Column(db.String(30), nullable=False)
imsi = db.Column(db.String(30), nullable=False)

@ -80,15 +80,15 @@ def edit(deviceId):
form.populate_for_updating(device)
_accountInfo = mainUtils.accountInfo(
title=device.name,
description=device.legal_entity.name,
short=device.website,
status=device.type.name,
description=device.company_owner.name,
short=device.device_owner.username,
status=device.status.name,
image_file=mainUtils.imageFileLink(device.image_file)
)
if form.validate_on_submit():
if form.picture.data:
picture_file = mainUtils.save_picture(form.picture.data)
if form.image_file.data:
picture_file = mainUtils.save_picture(form.image_file.data)
device.image_file = picture_file
mainUtils.fill_model(device, form)
@ -127,22 +127,3 @@ def add():
return render_template('edit.html',
theme=theme,
form=form)
@sensor.route('/search/<field_name>', methods=['GET'])
def search_field(field_name):
query = request.args.get('modalQueryArg', '')
# Assuming field_name corresponds to a model field, you would add conditional logic here to query the correct model.
if field_name == 'manufacturer_id':
results = Companies.query.filter(Companies.name.ilike(f'%{query}%')).all()
# Add more conditions for other fields as needed
return render_template('sensor/manufacturer_search_results.html', results=results, field_name=field_name)
@sensor.route('/select/<field_name>/<int:result_id>', methods=['GET'])
def select_field(field_name, result_id):
# Return the selected option
# This is a simplified example, you'll need to adapt this to your specific model fields and logic.
if field_name == 'manufacturer_id':
selected = Companies.query.get(result_id)
return render_template("sensor/manufacturer_options.html", selected=selected)

@ -1,3 +0,0 @@
<select class="btn btn-lg form-select" hx-get="/sensor/company_options" hx-swap="outerHTML" hx-target="#manufacturer_id" hx-trigger="click" id="manufacturer_id" name="manufacturer_id" required style="color:#191717; font-size: 14pt; background-color: #f1f1f1;" type="">
<option value="{{ selected.id }}" selected>{{ selected.name }}</option>
</select>

@ -1,7 +0,0 @@
<ul class="list-group">
{% for result in results %}
<li class="list-group-item">
<a href="#" hx-get="select/{{ field_name }}/{{ result.id }}" hx-target="#{{ field_name }}" hx-swap="outerHTML" class="text-decoration-none">{{ result.name }}</a>
</li>
{% endfor %}
</ul>

@ -14,10 +14,18 @@ def load_user(user_id):
class Users(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
username = db.Column(db.String(30), unique=True, nullable=False)
name = db.Column(db.String(30), nullable=False)
surname = db.Column(db.String(30), nullable=False)
email_account = db.Column(db.String(120), unique=True, nullable=False)
email_comm = db.Column(db.String(120), unique=False, nullable=False)
role = db.Column(db.String(120), unique=False, nullable=False, default='user')
street = db.Column(db.String(100), nullable=False)
street_no = db.Column(db.Integer, nullable=False)
post_code = db.Column(db.Integer, nullable=False)
city_id = db.Column(db.Integer, db.ForeignKey('cities.id'), nullable=False)
state_id = db.Column(db.Integer, db.ForeignKey('states.id'), nullable=False)
country_id = db.Column(db.Integer, db.ForeignKey('countries.id'), nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='def_avatar.png')
password = db.Column(db.String(60), nullable=False)
upload_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)

@ -5,7 +5,7 @@
<h1 class="account-heading" style="color: {{ theme.orange }};">{{ title }}</h1>
</div>
<div class="container rounded-3 " style="{{ theme.form.div_style }};">
{% include 'formModal.html' %}
{% include 'form.html' %}
{% if extraButtons %}
</div>
<div class="container text-left rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">

@ -1,21 +0,0 @@
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container text-center rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">
<h1 class="account-heading" style="color: {{ theme.orange }};">{{ title }}</h1>
</div>
<div class="container rounded-3 " style="{{ theme.form.div_style }};">
{% include 'form.html' %}
{% if extraButtons %}
</div>
<div class="container text-left rounded-3 mt-2 mb-2" style="{{ theme.form.div_style }};">
<div class="btn-group">
<br>
{% for button in extraButtons %}
<li><a href ="{{ button.link }}" class="{{ theme.form.submit_class }}" style="{{ theme.form.submit_style }}">{{ button.name }}<a>
{% endfor %}
<br>
</div>
{% endif %}
</div>
{% endblock content %}

@ -1,7 +0,0 @@
{% include 'form/stringField.html' %}
{% include 'form/selectFieldModal.html' %}
{% include 'form/dateField.html' %}
{% include 'form/boolField.html' %}
{% include 'form/fileField.html' %}
{% include 'form/urlField.html' %}
{% include 'form/integerField.html' %}

@ -1,6 +1,12 @@
{% if item.type in ['SelectField'] %}
<br>
{{ item.label(class=theme.form.select_label_class, style=theme.form.select_label_style) }}
<br>
{% if item.render_kw['custom_option'] == 'search_field' %}
<div class="input-group">
{{ item(class=theme.form.select_class, type=theme.form.select_type, style=theme.form.select_style)}}
<button class="btn btn-outline-secondary" type="button" data-bs-toggle="modal" data-bs-target="#{{ item.name }}SearchModal">Search</button>
</div>
{% include 'htmx/popup.html' %}
{% else %}
{{ item(class=theme.form.select_class, type=theme.form.select_type, style=theme.form.select_style)}}
{% endif %}
{% endif %}

@ -1,33 +0,0 @@
{% if item.type in ['SelectField'] %}
<br>
{{ item.label(class=theme.form.select_label_class, style=theme.form.select_label_style) }}
<br>
<div class="input-group mb-3">
{{ item(class=theme.form.select_class, type=theme.form.select_type, style=theme.form.select_style)}}
<button class="btn btn-outline-secondary" type="button" data-bs-toggle="modal" data-bs-target="#{{ item.name }}SearchModal">Search</button>
</div>
<div class="modal fade" id="{{ item.name }}SearchModal" tabindex="-1" aria-labelledby="{{ item.name }}SearchLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="{{ item.name }}SearchLabel">Search {{ item.label.text }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="text"
name="modalReqArg"
id="searchInput{{ item.name }}"
class="form-control"
placeholder="Search for {{ item.label.text }}..."
hx-get="search/{{ item.name }}"
hx-trigger="keyup changed delay:500ms"
hx-target="#{{ item.name }}Results">
<div id="{{ item.name }}Results"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% endif %}

@ -1,18 +0,0 @@
<form method="POST" action="" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<fieldset class="form-group">
{% for item in form %}
{% if item.id == 'submit' %}
{% elif item.id == 'csrf_token' %}
{% else %}
{% include 'form/allFieldsModal.html' %}
{% if item.errors %}
{% include 'form/formError.html' %}
{% endif %}
{% endif %}
{% endfor %}
</fieldset>
<div>
{% include 'form/submitField.html' %}
</div>
</form>

@ -0,0 +1,28 @@
<div class="modal fade"
id="{{ item.name }}SearchModal"
tabindex="-1"
aria-labelledby="{{ item.name }}SearchLabel"
aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="{{ item.name }}SearchLabel">Search {{ item.label.text }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<input type="text"
name="modalReqArg"
id="searchInput{{ item.name }}"
class="form-control"
placeholder="Search for {{ item.label.text }}..."
hx-get="/database/search/{{ item.name }}/{{ item.render_kw['query_table'] }}/{{ item.render_kw['query_key'] }}/{{ item.render_kw['query_return'] }} "
hx-trigger="keyup changed delay:500ms"
hx-target="#{{ item.name }}Results">
<div id="{{ item.name }}Results"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

@ -53,13 +53,11 @@ def initDatabase():
uploadCsvOnlyName(nbiotDevice)
hashed_pw = bcrypt.generate_password_hash('pass').decode('utf-8')
user = Users(username="Admin", email_account="admin@kynsight.com", email_comm="admin@kynsight.com", password=hashed_pw, role_id=1)
user = Users(username="Admin", name="Kerem", surname="Yollu", email_account="admin@kynsight.com", email_comm="admin@kynsight.com", password=hashed_pw, role_id=1, street="Meierackerstrasse", street_no="10", city_id="1", post_code="6810", state_id="1", country_id="1")
db.session.add(user)
hashed_pw = bcrypt.generate_password_hash('pass').decode('utf-8')
user = Users(username="KeremYollu", email_account="kerem.yollu@gmail.com", email_comm="kerem.yollu@gmail.com", password=hashed_pw, role_id=2)
user = Users(username="KeremYollu", name="Kerem", surname="Yollu", email_account="kerem.yollu@gmail.com", email_comm="kerem.yollu@gmail.com", password=hashed_pw, role_id=2, street="Meierackerstrasse", street_no="10", post_code="8610", city_id="1", state_id="1", country_id="1")
db.session.add(user)
hashed_pw = bcrypt.generate_password_hash('pass').decode('utf-8')
user = Users(username="Kynsight", email_account="kerem.yollu@kynsight.com", email_comm="kerem.yollu@kynsight.com", password=hashed_pw, role_id=3)
user = Users(username="Dadasli", name="Suleyman", surname="Yozgat", email_account="suleyman.yozgat@gmail.com", email_comm="suleyman.yozgat@gmail.com", password=hashed_pw, role_id=3, street="Kuskonmaz Sok.", street_no="11a", post_code="3451", city_id="1", state_id="1", country_id="1")
db.session.add(user)
db.session.commit()

Loading…
Cancel
Save