how to restrict other user from updating an db object in Flask? - python-3.x

I am new to flask and building an ticket assigner application. Generator end point will assign always the oldest ticket(status=q) from the system to the person logged in. Then either he will resolve(post method = s) the ticket or can update its status to pending (post method = p).
#main.route('/ticket/generator', methods=['GET', 'POST'])
#login_required
def generate_ticket():
ticket = Ticket.query.filter_by(status='q').order_by(Ticket.create_date).first()
form = GenerateTicketForm(obj=ticket)
if form.validate_on_submit():
ticket.ticket_id = form.ticket_id.data
ticket.status = form.status.data
db.session.add(ticket)
db.session.commit()
flash('Ticket Status Update Successfully.')
return redirect(url_for('main.generate_ticket'))
return render_template('generate_ticket.html', form=form)
I want to change the status when the ticket already assigned to someone, so that other do not get the same ticket. So I have created a class method to change the status when getting the oldest ticket:
#classmethod
def activate_tkt_flag(cls, ticket_id_, create_date_):
ticket_db_obj = cls(ticket_id=ticket_id_, create_date=create_date_)
ticket_in_memory = Ticket.query.get(ticket_db_obj.ticket_id)
ticket_in_memory.status = 'a'
db.session.commit()
return ticket_in_memory
If call that after the ticket object in the first query it rewrite the loop some how and assign a new ticket and forget about the previous one the it can not rewrite the the ticket any more and I am getting that error: Key (ticket_id)=(T5) already exists UPDATE ticket SET ticket_id=%(ticket_id)s, status=%(status)s WHERE ticket.ticket_id = %(ticket_ticket_id)s'] [parameters: {'ticket_id': 'T5', 'status': 's', 'ticket_ticket_id': 'T1'}]. If some one has better idea how to do it will be grateful, I am kind of stuck here. Here is the form looks like.

Finally I was able to solve it. I just create one end point which execute first and update the ticket status and pass the ticket id to the next end point. So the last end point show the ticket with updated status to render template html.
#main.route('/ticket/generator/<ticket_id>', methods=['GET', 'POST'])
#login_required
def generate_ticket(ticket_id):
ticket = Ticket.query.get(ticket_id)
form = GenerateTicketForm(obj=ticket)
if form.validate_on_submit():
ticket.ticket_id = form.ticket_id.data
ticket.status = form.status.data
db.session.add(ticket)
db.session.commit()
# flash('Ticket Status Update Successfully.')
return redirect(url_for('main.display_status', ticket_id=ticket.ticket_id))
return render_template('generate_ticket.html', form=form)
#main.route('/ticket/assign')
def assign_ticket():
ticket = Ticket.query.filter_by(status='q').order_by(Ticket.create_date).first_or_404()
ticket.status = 'a'
db.session.commit()
return redirect(url_for('main.generate_ticket', ticket_id=ticket.ticket_id))
The assign end point execute first then the ticket id handed over to generator end point.

Related

Python Django: deleting an object

I'm looking to delete an object in Django, but none of the other Stack Overflow questions fix mine. I looked at this one, but it doesn't seem to be working. My delete object code (in the views file) looks like this:
#login_required
def delete_entry(request, entry_id):
"""Delete an existing entry."""
if request.method != 'POST':
# No data submitted; create a blank form.
form = TopicForm()
else:
# POST data submitted; process data.
form = TopicForm(data=request.POST)
if form.is_valid():
new_topic = form.delete(commit=False) ### Code to delete object
new_topic.owner = request.user
new_topic.save()
return redirect('learning_logs:topics')
# Display a blank or invalid form.
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
And in URLs.py:
path('delete_entry/<int:entry_id>', views.delete_entry, name='delete_entry'),
I would like to use a Bootstrap 4 button (inside a modal) to delete the entry (so without any redirects to another confirmation page),
Unfortunately, this isn't working. I'm just getting a server error saying that NoReverseMatch at /delete_entry/6.
What does this mean?
It seems like you're trying to call the delete method on the form. If you want to delete the object, you should call it on the object:
my_object = MyModel.objects.get(id=entry_id) # Retrieve the object with the specified id
my_object.delete() # Delete it
Here is the relevant Django documentation.
I think that you're looking for a DeleteView.

Django - How do I set default value to primary key

I have made custom User model with AbstractBaseUser.
and I'm trying to make the primary key of the class to start from certain numbers as new users sign up to the site.
Such as '2022001' - '2022002' - '2022003' and so on.
I have searched on stack overflow and other sources, and some people suggest define function within the custom user's class model, but i have failed to do that.
is there a simple way to generate auto_increment number starting with the custom number from models.py ?
or Is it possible for me to give that certain number in views.py as new users sign up?.
here is my register function. from views.py
def register_user(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
messages.success(request, ("You have successfully registered."))
return redirect('home')
else:
form = RegistrationForm()
return render(request, 'register/register_user.html', {'form' : form})
Thank you
user = authenticate(id=2022001 ,username=username, password=password)
if you want to modify your primary key this method may help.
try this.....
add following field to your model:
id = models.BigIntegerField(primary_key=True)
now you give it what ever value you'd like

Deleting a ManytoMany Relationship Data in Django Project

I have tried to fix this issue for a while.
I have a model where there are logs entered by users and saved in Log Model. Also there is ActiveSession Model which has a ManytoMany relationship with Log Model.
In My views I am getting the POST and saving them in the Log Model. The next step is my issue where I am trying to add unqiue Logs inside the ActiveSession Model. By unique I mean by searching a field called 'log_order' in the Log Model.
The desired outcome is to:
1: Get the POST form and save the Log details in the Log Model
2: Search if the new saved Log has been previously added the many to many relation log under Active Session Model
3: If there is no Log in the ActiveSession Model to add the new Log in the Post to the activesession
4: If there are logs previously saved in ActiveSession to search for the log_order related to these logs
5: If there is no same log_order to add the new Log in the Post to the activesession
6: If the log_order is existing inside the activesession logs to delete this specific log and to add the new Log in the Post to the activesession
Models.py:
class Log(models.Model):
...................................
log_order = models.IntegerField(validators=[MinValueValidator(1)],blank=True, null=True)
date = models.DateTimeField(...........)
class LogForm(forms.Form):
.............................
log_order = forms.IntegerField()
class ActiveSession(models.Model):
log = models.ManyToManyField(Log)
..................................
Views.py:
def addlog(request, id):
active_session = ActiveSession.objects.get(id=ActiveSession.objects.last().id)
if request.method == 'POST':
form = LogForm(request.POST)
if form.is_valid():
data = Log()
data.log_order = request.POST.get('log_order')
data.log_repetitions = form.cleaned_data['log_repetitions']
data.log_weight = form.cleaned_data['log_weight']
data.save()
if active_session.log.values():
for i in active_session.log.values():
existing = i['log_order']
new = data.log_order
if int(existing) == int(new):
active_session.delete(active_session.log)
active_session.log.add(data)
active_session.save()
else:
active_session.log.add(data)
else:
active_session.log.add(data)
I have tried to save the data and update() but nothing is changing the dictionary the same exisiting outcome is printed and the new data is not replacing the existing ones. My objective is replace and avoid duplicating.
Update: I am also thought of if the keys is i['log_order'] is equal to data.log_order to delete the whole dictionary and add the new data whichever is easier
Trial:
With the below trial I got 'ManyRelatedManager' object is not subscriptable. I am not sure if I am going the wrong direction.
if active_session.log.values():
for i in range(len(active_session.log.values())):
new = data.log_order
if active_session.log[i]['log_order'] == new:
active_session.save()
else:
active_session.log.add(data)
else:
active_session.log.add(data)
Here is the current query:
<QuerySet [{'log_order': 1}, {'log_order': 1}]>
here is the requested query:
<QuerySet [{'log_order': 1}]>
I have tried and tested your code and found some issues with it.
Below, there is the code snippet I tested and it works.
I am not completely sure what is the purpose for the code, but I think you might find the method update_or_create useful (also works on related managers such as your log). Here is a link to Django docs.
def addlog(request, id):
if request.method == 'POST':
# Moved this part to the POST section of the view. It is sufficient to simplify
# the query in this way. Also, you probably want to check if there are sessions
# in the DB. Otherwise, the code would break. This returns a 404 in case there
# are absolutely no sessions.
active_session = ActiveSession.objects.last()
if active_session is None:
return Http404()
form = LogForm(request.POST)
if form.is_valid():
data = Log()
# Use form.cleaned_data instead of log_order. Form validates the data, POST dict doesn't.
data.log_order = form.cleaned_data['log_order']
# Ignored because it's missing from the model code
# data.log_repetitions = form.cleaned_data['log_repetitions']
# data.log_weight = form.cleaned_data['log_weight']
data.save()
# Use Django ORM querysets instead of values()
# See https://www.django-antipatterns.com/antipattern/over-use-of-values.html
active_session_logs = active_session.log.filter(log_order=data.log_order)
if active_session_logs.exists():
# Suggestion: try to use update() instead of a combination of delete & add.
# It reduces two SQL queries to one.
active_session_logs.delete()
active_session.log.add(data)
# After using RelatedManager.add(), no need to call save(), the changes
# are persisted in the DB simply by using add().
# Always redirect after successfully processing the form.
return redirect(reverse('test_73764999:add-log', args=(data.id,)))
else:
# If there are errors, re-render the same form with errors
return render(request, 'test_73764999/form.html', {
'form': form, 'id': id,
})
else:
# If this is a GET request, render an empty form
form = LogForm()
return render(request, 'test_73764999/form.html', {
'form': form, 'id': id,
})

Sorting and Deleting a 1-to-Many relatiionship in SQLALCHEMY and flask

I am working a CRUD flask project that works with a 1-to-many relationship. The end result looks like this, Flask Webform. However when I submit the form for the Update route, it returns to the home page and displays this. Webform After Update.
Here is my DB model
def update(id):
frank = Frankendama.query.get(id)
form = FrankForm()
if form.validate_on_submit():
frank.title=form.title.data
frank.description=form.description.data
frank.tama=form.tama.data
frank.sarado=form.sarado.data
frank.sword=form.sword.data
frank.string=form.string.data
frank.bearing=form.bearing.data
db.session.add(frank)
db.session.commit()
comps = form.companies.data
comps_used = comps.split(",")
all_comps = Company.query.all().filter_by(Company.frankendama_id == id) #Error here
for entry in all_comps:
if entry.frankendama_id == id:
db.session.delete(entry)
for i in range(0, len(comps_used)):
new_entry = comps_used[i]
new_comp = Company(name=new_entry, frankendama_id=id)
db.session.add(new_comp)
db.session.commit()
return redirect(url_for("home"))
else:
return render_template("create.html", form=form)
I am trying to find a query for the Companies table that sorts for all rows with the foreign key 'frankendama_id' that is same to the main tables id. That way i can delete them and then re add them.
When i try using filter() or filter_by() i get the error AttributeError: 'list' object has no attribute 'filter_by'
I am really stumped, any suggestions are welcome! Thanks
move filter_by in front of .all()
all_comps = Company.query.filter_by(frankendama_id = id).all()
edit 1:
Also you can remove 'Company.' when using filter_by and you only need a single equals sign

How do I efficiency create big forms - FlaskForms

So I have an update form end point, which is very large, I've tried a few things to make it dynamically created to condense my code but I cant seem to figure it out.
#customers.route("/<int:customer_id>/update_customer", methods=['GET', 'POST'])
# not programmatic - needs work - I do not like this
def update_customer(customer_id):
post = Post.query.get_or_404(customer_id)
if post.author != current_user:
abort(403)
form = CustomerForm()
if form.validate_on_submit():
post.tpi_name = form.tpi_name.data
post.tpi_ref = form.tpi_ref.data
post.company_name = form.company_name.data
post.company_type = form.company_type.data
post.company_reg = form.company_reg.data
post.sic_code = form.sic_code.data
post.vat_number = form.vat_number.data
db.session.commit()
flash("That customer's record has been updated!", 'success')
return redirect(url_for('customers.view_customer', customer_id=post.id))
elif request.method == 'GET':
form.tpi_name.data = post.tpi_name
form.tpi_ref.data = post.tpi_ref
form.company_name.data = post.company_name
form.company_type.data = post.company_type
form.company_reg.data = post.company_reg
form.sic_code.data = post.sic_code
form.vat_number.data = post.vat_number
return render_template('customers/customers.html', form=form, username=current_user.username,image_file=current_user.image_file, email=current_user.email)
So say if we had 100+ fields in the form, how would I change this code so I don't have to explicitly state each field.
Based on pjcunningham's answer, and looking into wtform docs, I found this piece of code:
def edit_profile(request):
user = User.objects.get(pk=request.session['userid'])
form = EditProfileForm(request.POST, obj=user)
if request.POST and form.validate():
form.populate_obj(user)
user.save()
return redirect('/home')
return render_to_response('edit_profile.html', form=form)
Based on that, I guess you want to write this code:
if form.validate_on_submit():
form.populate_obj(post)
db.session.commit()
flash("That customer's record has been updated!", 'success')
return redirect(url_for('customers.view_customer', customer_id=post.id))
For the second part of your code (the "GET" branch), it depends on your intentions. You can populate your form with data from object when you create it:
form = CustomerForm(obj=post)

Resources