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.
Related
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,
})
I have a middleware I'm using to retain route history within my Django app to use with breadcrumbs, but for some reason the last item in the list keeps getting replaced rather than the item appending to the end of the list.
ROOT_ROUTE_PATH = '/labels/'
class RouteHistoryMiddleware(object):
request = None
history = None
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
self.request = request
if 'history' not in request.session:
request.session['history'] = []
self.history = request.session['history']
request.session['history'].append(request.path)
if len(self.history) == 0:
self.request.previous_route = ROOT_ROUTE_PATH
elif len(self.history) == 1:
self.request.previous_route = request.session['history'][-1]
elif len(self.history) > 1:
self.request.previous_route = request.session['history'][-2]
return self.get_response(request)
Illustration of request.session['history'] mutation with above:
Open Page A
['/page_a/']
Open Page B
['/page_a/', '/page_b/']
Open Page C
['/page_a/', '/page_c/']
Instead of appending path to session try appending to self.history then overwrite history with new array:
...
self.history = request.session['history']
self.history.append(request.path)
request.session['history'] = self.history
...
You may need to change your if/else conditions after that
The issue you're running into is that Django doesn't know you've modified the list, and so the data is getting written to the session inconsistently. From the documentation:
By default, Django only saves to the session database when the session has been modified – that is if any of its dictionary values have been assigned or deleted.
i.e, if you modify the list without reassigning it or deleting it, then it will not know the session has been modified. Again from the documentation:
we can tell the session object explicitly that it has been modified by setting the modified attribute on the session object.
So your original code should work if you add this line after modifying the list in place:
request.session.modified = True
(Replacing the list entirely, as suggested in the other answer, also works - I'm just trying to explain why your original code didn't work).
I will try to explain this issue the better I can.
So I built a calculator using django. The user can put the desired input, and then he sees all the results in a table, only by pressing the button: 'select'.
If the user only wants this result, the user see the result output in the table.
However, if the user selects one of the options presented in the dropdowns, then the result should be different. Meaning that the dropdown list, has specific calculus.
This is the part that I don't understand,I know that I have to use JS to this, but I don't know in which module this should be added.
Here is my code:
models.py
class CalcAnalyzer(models.Model):
sequence = models.TextField()
gc_calc = models.CharField(max_length=2000000)
person_of = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
def save(self, *args, **kwargs):# new
if self.sequence != None:
self.gc_calc = gc_calc(self.sequence)
super(CalcAnalyzer,self).save(*args, **kwargs)
def __str__(self):
return self.sequence
class addcalc_1(models.Model):
name_sequence = models.ForeignKey(OligoAnalyzer, on_delete=models.SET_NULL, null=True)
Option1_5 = models.FloatField(default=0)
def save(self, *args, **kwargs):
self.Option1_5 = Option1_5(self.sequence)
class addcalc_3(models.Model):
name_sequence = models.ForeignKey(OligoAnalyzer, on_delete=models.SET_NULL, null=True)
optional_3
def save(self, *args, **kwargs):
self.optional_3 = optional_3(self.sequence)
views.py
def calc_sequence(request):
sequence_items=Calanalisis.objects.filter(person_of=request.user)
form=AddSequenceForm(request.POST)
if request.method=='POST':
form=AddSequenceForm(request.POST)
if form.is_valid():
profile=form.save(commit=False)
profile.person_of = request.user
profile.save()
return redirect('calc_sequence')
else:
form=AddSequenceForm()
myFilter=SequenceFilter(request.GET,queryset=sequence_items)
sequence_items=myFilter.qs
context = {'form':form,'sequence_items':sequence_items,'myFilter':myFilter}
return render(request, 'Add_Calc.html', context)
How can I insert this in the view.py? If the user selects the 5 or 3 box, the result should appear in the table bellow, if not, the result will stay the same.
Sofia, hi!
To subscribe on the dropdown's events you need a piece of javascript.
HTML and static files
So, you need to attach your new script.js file to your project. You can check what you need to serve static files (it's not a "one-click" solution, especially if you want to deploy your code for external users) docs
When your static file is ready you can include it in the front-end.
Let's imagine that you have index.html where your controls live.
Add the link to the file in your html (before closing </body> tag):
<script type="text/javascript" src="/static/script.js"></script>
static.js
This example shows you how to make an event listener and listen to the dropdown changes.
Use values from the selected options of your dropdowns to make a URL for the request. Ex. /calc/api/?param=1, so you will be able to catch param=1 in your view and react properly.
dropdown example:
<select id="param" name="here_name">
<option value="">Select …</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
API
Create an additional view to handle the requests that will be sent on events. Make it accessible with urls.py.
Use the proper URL to the endpoint in the javascript. Here you can find how to make requests from the JS to your Django back-end.
The param that was chosen will be in the request.GET of your view (if you've chosen GET method to send the data). So make a proper answer and send it back to the JS. You can use JSON format for this.
Parse the answer in the JS and change your page with updated information.
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
I was trying to implement Ajax form submission as context given AJAX Form Submission(inline success) but it is not working in my case, here is my code.
#view_config(route_name='add_user', permission='admin', renderer='add_user.mako')
def add_user(self):
#adding succeed method as per given context in above link.
def succeed():
return Response('<div id="thanks">Thanks!</div>')
schema = UserSchema(validator = user_DoesExist).bind(request=self.request)
#Form defined with use_ajax=True.
form = deform.Form(schema, action=self.request.route_url('add_user'), buttons=('Add User','Cancel'), use_ajax=True)
if 'Cancel' in self.request.params:
return HTTPFound(location = self.request.route_url('home'))
if 'Add_User' in self.request.params:
appstruct = None
try:
appstruct = form.validate(self.request.POST.items())
except deform.ValidationFailure, e:
log.exception('in form validated')
return {'form':e.render()}
newuser = User(username=appstruct['username'],
name=appstruct['name'],
extension=appstruct['extension'],
pin=appstruct['pin'],
status=1)
DBSession.add(newuser)
DBSession.flush()
return dict(form=form.render(success=succeed))
return dict(form=form.render(appstruct={}))
Output:
On form submission code gets executed but form on screen remains in unchanged but it does not execute succeed() method. :(
And if try it with exactly same context as stated in the above link such as
#view_config(route_name='add_user', permission='admin', renderer='add_user.mako', name='ajaxform')
#demonstrate('AJAX form submission (inline success)')
def ajaxform(self):
#adding succeed method as per given context in above link.
def succeed():
return Response('<div id="thanks">Thanks!</div>')
schema = UserSchema(validator = user_DoesExist).bind(request=self.request)
#Form defined with use_ajax=True.
form = deform.Form(schema, action=self.request.route_url('add_user'), buttons=('Add User','Cancel'), use_ajax=True)
if 'Cancel' in self.request.params:
return HTTPFound(location = self.request.route_url('home'))
if 'Add_User' in self.request.params:
appstruct = None
try:
appstruct = form.validate(self.request.POST.items())
except deform.ValidationFailure, e:
log.exception('in form validated')
return {'form':e.render()}
newuser = User(username=appstruct['username'],
name=appstruct['name'],
extension=appstruct['extension'],
pin=appstruct['pin'],
status=1)
DBSession.add(newuser)
DBSession.flush()
return self.render_form(form, success=succeed)
return dict(form=form.render(appstruct={}))
Output:
NameError: name 'demonstrate' is not defined
if i remove this line
#demonstrate('AJAX form submission (inline success)')
than i gives me error:
AttributeError: 'UsersView' object has no attribute 'render_form'
Need help to perform a ajax form submission using deform_bootstrap.
Thanks,
correct me if i am wrong somewhere. :)
I had the exact same issue. The problem is that the form's render function doesn't actually take a success keyword argument i.e.
form.render(success='<div>here</div')
Isn't actually going to what you think. If you look at the demo code you can see that they call another function
self.render_form(form, success='<div>here</div>')
This is a completely separate function to the form rendering function. It process the call (let's assume a valid post) and then if the validation is success checks to see if 'success' is defined and returns that as the HTML in a response object. Otherwise it returns 'form.render' in the response object.
Hope that helps.
Keith