How to pass data from a QuerySelectField in flask? - python

In my application i have a QuerySelectField to populate a dropdown menu.
I get the choices details for the queryselectfield from the db. Once user select any choice from dropdown menu and click on Submit button which is a POST method, i want to pass the value that user selected from the dropdown to a db to store. But it always return the value None from the queryselectfield. So db stores the data as None.
models.py
class Orders(db.Model):
__tablename__ = 'orders'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
email = db.Column(db.String(120))
resturant = db.Column(db.String(64))
food = db.Column(db.String(64)))
forms.py
def possible_res():
return Resturant.query.all()
def possible_menu():
return Menu.query.all()
class OrderForm(Form):
sel_res = QuerySelectField(query_factory=possible_res,
get_label='name')
sel_menu = QuerySelectField(query_factory=possible_menu,
get_label='food',
allow_blank=False
)
submit = SubmitField("Confirm")
views.py
#app.route('/resturant', methods=['GET','POST'])
def resturant():
form = OrderForm()
if request.method == 'GET':
test = form.sel_menu.data
return render_template("make_order.html", form=form, test=test)
else:
a = User.query.filter_by(email = session['email']).all()
for u in a:
name = u.firstname
b = Orders(name=name, email=session['email'])
b.resturant = form.sel_res.data
b.food = form.sel_menu.data
db.session.add(b)
db.session.commit()
return redirect('/')

QuerySelectField#__init__'s query_factory argument should return a SQLAlchemy Query object, not a Python list. WTForms will materialize the query itself, by iterating over it. Simply change your factory functions to return the query attribute, rather than the list:
def possible_res():
return Resturant.query
def possible_menu():
return Menu.query

Related

Django: Popup for FK CRUD form inside another form

I'm learning Django, so I'm trying to create a mini-app for practice.
I've 2 tables on DB:
By one side webapp_domicilio, where is a PK for the ID and some varchars for address info.
By the other side, webapp_persona, where is a PK for the ID, some varchars for person info and a FK referencing the address ID (webapp_domicilio.id)
I created the webpage for adding new item to webapp_persona, inheriting ModelForm and now I want to add the option to create, edit and delete an address without exiting this page, just like the Django Admin page.
Searching on stackoverflow I found this article: Creating front-end forms like in Django Admin but the accepted answer get me to a 404 page on Django documentation.
Then I tried what's in https://django-addanother.readthedocs.io/en/latest/index.html and I managed to insert the 'add' button but it doesn't open in a popup using CreatePopupMixin from django_addanother.views. There is a point where they explain how to make the view popup compatible but I don't really understand it. I also tried to insert the 'edit' button but it doesn't work neither.
I let my code here:
views.py:
def nueva_persona(request):
if request.method == 'POST':
formulario_persona = PersonaForm(request.POST)
if formulario_persona.is_valid():
formulario_persona.save()
return redirect('personas')
else:
formulario_persona = PersonaForm()
return render(request, 'nueva_persona.html', {'formulario_persona': formulario_persona})
def editar_domicilio(request, id):
domicilio = get_object_or_404(Domicilio, pk=id)
if request.method == 'POST':
formulario_domicilio = DomicilioForm(request.POST, instance=domicilio)
if formulario_domicilio.is_valid():
formulario_domicilio.save()
return redirect('domicilios')
else:
formulario_domicilio = DomicilioForm(instance=domicilio)
return render(request, 'editar_domicilio.html', {'formulario_domicilio': formulario_domicilio})
def nuevo_domicilio(request):
if request.method == 'POST':
formulario_domicilio = DomicilioForm(request.POST)
if formulario_domicilio.is_valid():
formulario_domicilio.save()
return redirect('domicilios')
else:
formulario_domicilio = DomicilioForm()
return render(request, 'nuevo_domicilio.html', {'formulario_domicilio': formulario_domicilio})
def eliminar_domicilio(request, id):
domicilio = get_object_or_404(Domicilio, pk=id)
if domicilio:
domicilio.delete()
return redirect('domicilios')
models.py:
class Domicilio(Model):
calle = CharField(max_length=255)
nro = IntegerField()
localidad = CharField(max_length=255)
def __str__(self):
return f'{self.calle} {self.nro} {self.localidad}'
class Persona(Model):
nombre = CharField(max_length=255)
apellido = CharField(max_length=255)
email = CharField(max_length=255)
domicilio = ForeignKey(Domicilio, on_delete=RESTRICT)
def __str__(self):
return f'{self.id} {self.nombre} {self.apellido} {self.email}'
forms.py:
class PersonaForm(ModelForm):
class Meta():
model = Persona
fields = '__all__'
widgets = {
'email': EmailInput(attrs={'type':'email'}),
'domicilio': AddAnotherWidgetWrapper(
Select,
reverse_lazy('nuevo_domicilio'),
),
# 'domicilio': EditSelectedWidgetWrapper(
# Select,
# reverse_lazy('editar_domicilio', args=['__fk__']),
# ),
}
class DomicilioForm(ModelForm):
class Meta():
model = Domicilio
fields = '__all__'
widgets = {
'nro': NumberInput(attrs={'type':'number'}),
}
What I'd like to do is create a form similar to this:
When user try to create a new person, it should open a form like this:
And, if user click on '+' button, it should open a popup like this:
Once user saves the new address, it should close the popup and show it in drop down list of the 'domicilio' field
Thaks and regards

Retrieving current user id inside a function defined into class (CreateView)

Is possible to retrieve the current logged user id into a function defined inside a class, in views.py, using Django CreateView?
Something like this:
class CreationClass(CreateView):
model = Mymodel
def creation(self, request):
if request.method == 'POST':
form = MyForm(request.POST or None)
if form.is_valid:
form = myForm()
user_id = self.request.user.id
rel_table = Item_id_user ( item_id = form.id, user_id = request.user.id)
rel_table.save() #<--- this does not save, even if table exists
return render(request, ''mypage.html')
And this is my models.py
class Item(models.Model):
id_user = models.ManyToManyField(User, related_name='user_item',
verbose_name='id utente', through='Item_id_user')
object = models.Manager()
# table to handle relationship
class Item_id_user(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
id = models.IntegerField(primary_key=True)
What I want to achieve is to store into Item_id_user, but nothing at all is being stored. I thought the problem was the request.user.id.
instead of:
user_id = self.request.user.id
try this:
user_id = request.user.id
Should work.
I don't understand why you re-initialize the form with form = MyForm() after the form is validated. I think that might wipe the data contained in it. It looks like you forgot it there.
Try this:
class CreationClass(CreateView):
model = Mymodel
def creation(self, request):
if request.method == 'POST':
form = ColumnCreationForm(request.POST or None)
if form.is_valid:
# form = myForm()
user_id = self.request.user.id
rel_table = Item_id_user ( item_id = form.id, user_id = request.user.id)
rel_table.save() #<--- this does not save, even if table exists
return render(request, ''mypage.html')

NOT NULL constraint failed: registratie_inkomen.pg_id

This are my models:
class PersoonGegevens(models.Model):
# Voornaam en achternaam
voornaam = models.CharField(max_length=265,)
achternaam = models.CharField(max_length=265)
#username
user = models.OneToOneField(User, on_delete=models.CASCADE)
class inkomen(models.Model):
pg = models.ForeignKey(PersoonGegevens, on_delete=models.CASCADE)
inkomenfield = models.CharField(max_length=100)
This is the form:
class inkomenForm(forms.ModelForm):
class Meta():
model = inkomen
fields = ('inkomenfield',)
This is my view:
def tijdelijk(request):
#User id
user = request.user.id
if request.method == 'POST':
incoming = inkomenForm(data=request.POST)
if incoming.is_valid():
incoming.save()
return HttpResponse("saved")
else:
x = incoming.errors
print (x)
return HttpResponseRedirect('/tijdelijk')
else:
incoming = inkomenForm()
return render(request, 'index/tijdelijkeindex.html', {'inkomen':incoming})
I have tried:
incoming.save(commit=False)
incoming.pg = user
incoming.save
also readed the documentation about Inline formsets of django. But i dont really get
So i get the following error:(NOT NULL constraint failed) and i know it comes because i need to assign the pg.id and i know i can do that by adding the field in the form.py and let the user choose the id. But what i actually want is that pg = the logged in user.
You need to assign the return value of form.save(commit=False) to a variable, the return value is the created (but not committed to the database) model object
obj = incoming.save(commit=False)
obj.pg = user
obj.save()

flask add a new row based on id of other tables

I have two tables, named projects and actions and every project contain several action
class Projet(db.Model):
__tablename__ = 'projets'
id = db.Column(db.Integer, primary_key=True)
nom_projet = db.Column(db.String(100))
description_projet = db.Column(db.String(800))
date_affectation = db.Column(db.DateTime, nullable = False)
statut_projet = db.Column(db.String(100))
admin_id = db.Column(db.Integer, db.ForeignKey('admins.id'))
actions = db.relationship('Action', backref='projet',
lazy='dynamic')
def __repr__(self):
return '<Projet: {}>'.format(self.id)
class Action(db.Model):
__tablename__ = 'actions'
id = db.Column(db.Integer, primary_key=True)
projet_id = db.Column(db.Integer, db.ForeignKey('projets.id'))
description = db.Column(db.String(1000))
statut_action = db.Column(db.String(100))
date_action = db.Column(db.DateTime, nullable = False)
date_execution = db.Column(db.DateTime, nullable = True)
def __repr__(self):
return '<Action: {}>'.format(self.id)
my problem is, I need to create a new action based on an existing project as shown in image,
I need to click on add button and he must redirect me to action form with the name of project auto-selected, and I entre the action details.
this is my first code to add action:
#auth.route('/action/add', methods=['GET', 'POST'])
#login_required
def add_action():
form = ActionForm()
if form.validate_on_submit():
action = Action(
projet = form.projet.data,
description = form.description.data,
statut_action = form.statut_action.data,
date_action = form.date_action.data,
date_execution = form.date_execution.data
)
try:
db.session.add(action)
db.session.commit()
flash('You have successfully added a new action.')
except:
flash('Error: action name already exists.')
return redirect(url_for('auth.list_projets'))
return render_template('admin/actions/action.html', action="Add", form=form,
title="ADD ACTION")
Steps:
Update the URL to include project_id as path param: ex: /project/1/actions/add is meant to load a page with new action form for project with id 1
Update the links to add new action in the previous page(as shown in the screenshot) as per step 1
Remove project field from ActionForm as it is handled using path param
Update "new action form" page to show product name coming in product_name variable
Try,
#auth.route('/project/<project_id>/action/add', methods=['GET', 'POST'])
#login_required
def add_action(project_id):
form = ActionForm()
project = Project.query.get(project_id)
if not project:
flash('Error: invalid project')
abort(404)
if form.validate_on_submit():
action = Action(
project = project,
description = form.description.data,
statut_action = form.statut_action.data,
date_action = form.date_action.data,
date_execution = form.date_execution.data
)
try:
db.session.add(action)
db.session.commit()
flash('You have successfully added a new action.')
except:
flash('Error: action name already exists.')
return redirect(url_for('auth.list_projets'))
return render_template('admin/actions/action.html', action="Add", form=form,
title="ADD ACTION", project_name=project.name)

Convert variable into class variable (no idea what to name it)

Using
Flask
Flask-sqlalchemy
Sqlalchemy
Jquery
Datatables (jquery plugin)
Jeditable (jquery plugin)
Consider this user class ( straight out of flask-sqlalchemy docs):
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
The datatables makes an ajax request and populates the table. Each td then is made editable in place with jeditable. As soon as a td is modified, jeditable makes a POST request to localhost/modify containing:
The row id(the same id from the user class)
The new modified value
The column of the table that was altered ( for the sake of argument let's assume that there are three columns id/username/email) (int)
Now, i'd like that in the function that handles localhost/modify i take the row id, make a user object and query the db for that specific row, see what property needs to be modified, modify it with the new value and commit to the db. Here's what i got so far:
#app.route('/modify', methods=['GET', 'POST'])
def modify()
if request.method == 'POST' :
user = user.query.get(form.row_id)
if form.column_id == int(0):
user.id = form.value
elif form.column_id == int(1):
user.username = form.value
elif form.column_id == int(2):
user.email = form.value
else:
pass
db.session.commit()
return 'ok'
This way, yes it does work but theremust be amore beautiful approach. This one doesn't seem very...pythonic
Mihai
Use a map of column ID to attribute name.
colmap = {
0: 'id',
1: 'username',
2: 'email',
}
#app.route('/modify', methods=['GET', 'POST'])
def modify()
if request.method == 'POST' :
user = user.query.get(form.row_id)
try:
setattr(user, colmap[form.column_id], form.value)
except KeyError:
pass
db.session.commit()
return 'ok'

Categories

Resources