Flask-WTForms QuerySelectField - not showing selected option on edit - flask-wtforms

I current have a User Model that is Updated with a user_role in the database. this update is done using WTForms and SqlAlchemy using the QuerySelectField. I can update the database and everything is working fine. However when I want to update the role of a user and i edit that user the QuerySelectField from the form does not show the current value of the user_role for the in the database, it shows the first option in the database of user_roles.
UserForm used for adding a user_role to a user
class UserForm(FlaskForm):
user_role_opts = QuerySelectField(query_factory=lambda: UserRole.query,
get_pk=lambda x: x.id, get_label="role_name")
submit = SubmitField()
Models
class User(UserMixin,db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
clients = db.relationship('Client',
secondary=user_clients,
back_populates='users')
user_role_id_user = db.Column(db.Integer, db.ForeignKey('user_role.id'))
class UserRole(db.Model):
id = db.Column(db.Integer, primary_key=True)
role_name = db.Column(db.String(64), index=True, unique=True)
users = db.relationship('User', backref='user', lazy='dynamic')
def __repr__(self):
return '<UserRole: {}>'.format(self.name)
Routes for update
#settings_blueprint.route('/user/<int:id>/edit', methods=['GET','POST', 'PATCH'])
def edit_user(id):
found_user = User.query.get(id)
form = UserForm(obj=found_user)
if request.method == b"PATCH":
found_user.user_role_id_user = request.form['user_role_opts']
db.session.add(found_user)
db.session.commit()
flash('User has been updated')
return redirect(url_for('settings.index'))
return render_template('settings/edit_user.html', id=id, found_user=found_user, form=form)
edit_user.html page
{% block app_content %}
<h1>Edit User {{ found_user.username }}</h1>
<div class="row">
<form action="{{ url_for('settings.edit_user', id=found_user.id) }}?_method=PATCH" method="POST">
{{ form.hidden_tag() }}
<p>
{{ form.user_role_opts }}
</p>
<button>Edit User</button>
</form>
</div>
{% endblock %}
So in the database the user"Mark" has a role of "Senior manager"(id=2 in the database)
pic database
When I try and edit this user, the QuerySelectField automatically shows the role as "Director" (this is id 1 in the database)
pic edit
When i edit the user i need to see the pre-selected value of "Senior Manager"
Any help would be greatly appreciated, i have gone around in circles with it.
Thanks

Related

password fields in wtform do not populate correctly

I've got the Settings page where users can change their data (including the password). They should be able to change some data without providing the password everytime. But it looks like the PasswordField is not populated correctly and I cannot figure out where to look for a problem. I open the settings page and if I want to change anything in the form I receive the "Passwords must match" error everytime. After debugging I can see that the password_change has the correct value but the password_confirm is empty. I need to manually provide password_confirm value every time. It shouldn't be required. How do wtforms populate the PasswordField and why that doesn't work?
view.py
else: # GET
form = UserEditForm(obj=acc)
return render_template('account/view.html', account=acc, form=form)
class UserEditForm(Form):
name = StringField('Account name', [DataOptional(), validators.Length(min=3, max=64)])
email = StringField('Email address', [
IgnoreUnchanged(),
validators.Length(min=3, max=254),
validators.Email(message='Must be a valid email address'),
EmailAvailable(),
validators.EqualTo('email_confirm', message='Email confirmation must match'),
])
email_confirm = StringField('Confirm email address')
password_change = PasswordField('Change password', [
validators.EqualTo('password_confirm', message='Passwords must match'),
])
password_confirm = PasswordField('Confirm password')
<div class="form__question">
{{ render_field(form.password_change, placeholder="********") }}
</div>
<div class="form__question">
{{ render_field(form.password_confirm, placeholder="********") }}
</div>
You could try something like this, making the password field optional, and then only require the password_confirm field if data exist in the password_change field
password_change = PasswordField(
'password',
validators=[DataOptional(), validators.Length(min=6, max=255)]
)
password_confirm = PasswordField(
'Repeat password',
validators=[
RequiredIf('password_change'),
EqualTo('password_change', message='Passwords must match.')
]
)
create a validator class for RequiredIf
source -> How to make a field conditionally optional in WTForms?
class RequiredIf(InputRequired):
# a validator which makes a field required if
# another field is set and has a truthy value
def __init__(self, other_field_name, *args, **kwargs):
self.other_field_name = other_field_name
super(RequiredIf, self).__init__(*args, **kwargs)
def __call__(self, form, field):
other_field = form._fields.get(self.other_field_name)
if other_field is None:
raise Exception('no field named "%s" in form' % self.other_field_name)
if bool(other_field.data):
super(RequiredIf, self).__call__(form, field)

Placeholder in Symfony annotation translation message

I'm using Symfony with annotation and assert to do some validation checks in a form. With the following annotation I'm checking if a field is not blank:
#Assert\NotBlank(message="not_blank")
This generated a message in the correct language, this case:
The field cannot be empty
Now I want to add the field name as a placeholer so I don't need to make a separate message for every field. So something like:
#Assert\NotBlank(message="not_blank {{ name=email }}")
<trans-unit id="1">
<source>not_blank</source>
<target>This {{ name }} field cannot be empty</target>
</trans-unit>
In the translation file it would then be:
Then I can output:
The email field cannot be empty
If this is possible then I don't need to make separate message for every field like: name, email, street etc..
If you open #Assert\NotBlank you can see:
class NotBlank extends Constraint
{
public $message = 'This value should not be blank.';
}
So you can't use it in another way, but you can create custom constraint by extending the base constraint class Constraint
See Tutorial

Wordpress New Registration Form with Radio Button

I'm a Wordpress newbie and I am stumped. I've tried to Google it for help, looking for plugins. I haven't been successful.
I'd like to create 2 choices for the user: Member or Vendor, and based on their selection, it sends an email when they finish upon registration.
So if I select Member, then it sends an email to member#gmail.com or if they select vendor,vendor#gmail.com will be submitted.
Can somebody help me please?
There will be a registration form in which add this selection
//form starts
//other fields
<input type = "radio" name = "user_role" value = "Member">Member</input>
<input type = "radio" name = "user_role" value = "Vendor">Vendor</input>
//submit
//on submit
if(isset($_POST['user_role'])){
//Here check value selected from both choices
if($_POST['user_role'] == "Member"){
$email_id = "member#gmail.com";
}
else{
$email_id = "vendor#gmail.com";
}
//send email
}

How to use custom repository methods in Twig template?

Assuming I have an entity User and an entity Book and they're both joined by User.bookId = Book.id (this marks a user owns a certain book, relation type oneUserToManyBook).
If I now want to execute a performance friendly fetch with Doctrine's DQL or QueryBuilder for all Books a User has read, what is the best way to implement this in a Symfony2/Doctrine2 webapp, so that I can use them in my User loop in a Twig template?
Twig
{% for user in users %}
{{ user.name|e }}
{% for address in user.getAddressesByUserId(user.getId()) %}
{{ address.city }}
{% endfor %}
{% endfor %}
I see two approaches, but both don't lead to my target:
1st approach
Create a custom repository class BookRepository:
public function getBooksOwnedByUser($user_id) {
return $em->createQuery('SELECT b.title
FROM MyBundle\Entity\User u,
MyBundle\Entity\Book b
WHERE u.book_id = b.id'
AND u.id = :user_id)
->setParameter('user_id', $user_id)
->getResult();
}
Problem: Works fine, but I cant call getBooksOwnedByUser() in my Twig template (because it's not tied to the entity User, but to it's repository, which is a subclass of Doctrine\ORM\EntityRepository.
2nd approach
Execute the same query as above - not in my UserRepository, but directly in my User entity class.
Problem here: I could call this method in my Twig template, but I cannot (and should not) use the EntityManager in my User entity class.
It's best if you make a relationship from User to Books. Assuming you have made this relationship you can make your query like this:
public function getBooksOwnedByUser($user_id) {
return $em->createQuery('SELECT u, b
FROM MyBundle\Entity\User u
JOIN u.books b
WHERE u.id = :user_id')
->setParameter('user_id', $user_id)
->getResult();
}
Then in your controller:
$em = $this->getDoctrine()->getManager();
$user_with_books = $em->getRepository('MyBundle\Entity\User')
->getBooksOwnedByUser($user->getId());
return $this->render('YourTemplate.html.twig', array(
'user_with_books' => $user_with_books,
));
In twig:
{% for book in user.books %}
{{ book.title }}
{% endfor %}
Some considerations:
For multiple users you will have to change the query (lazy loading is possible but not advised).
If it's a lot of data you can get a performance boost by getting a scalar result (Array)
If you need different queries for the user that can not be combined you will have to store different variables (objects or arrays). That's why I named it "user_with_books". But if you only have this user in your template you can just as well call it "user".
user.getAddressesByUserId(user.getId()) <-- passing data from one model to query is the responsiblity of the controller (or a service). Best practice is to avoid doing this in your template.
So the answer:
You can not do anything with a custom repository method because it's a function. A function on itself doesn't represent any data. So this is a way you can retrieve the actual data with that function and display that.

Check joined entity from Twig in Symfony2

I want to display a table with some entity relations from a Doctrine DQL query.
My "main" entity Lead has a relation with Tour like this:
class Lead {
/**
* #var integer $tourId
* #ORM\Column(name="`tour_id`", type="integer")
*/
private $tourId;
/**
* #var Tour $tour
* #ORM\ManyToOne(targetEntity="Tour")
* #ORM\JoinColumn(name="tour_id", referencedColumnName="id")
*/
private $tour;
...
}
And I get the data from DB with a Doctrine2 DQL:
SELECT l, c
FROM BuvMarketplaceBundle:Lead l '
JOIN l.client c
Note that I don't JOIN with Tour becouse not all Leads have a Tour associated, this field can be null.
Then I am printing like this:
{% for lead in leads %}
{{ lead.id }}
{% if lead.tour %}
{{ lead.tour.name }}
{% endif %}
{% endfor %}
The problem comes where lead.tour has a numeric value, but this value does not exists in the tours table (because it has been deleted). I get the "Entity was not found." exception that refers to the lead.tour that does not exist in the DB.
I tried to check lead.tour with is defined, is not null but nothing works.
Twig is not supporting the cheking of types, so there is no basic function available to check lead.tour is object or similar.
Is there any way that can check an object from Twig or left join from the DQL?
A left join will solve the problem of not all leads having a tour.
SELECT lead,tour
FROM BuvMarketplaceBundle:Lead lead
LEFT JOIN lead.tour tour
And as my comment indicates, in a properly setup Doctrine 2 model, it will not be possible for lead to point to a tour record that does not exist.

Resources