Django POST save and delete - django

I'm attempting to save records into a model using the modelform (this part is working as intended) and delete records from the same model using a checkbox (can't figure this piece out). I am creating a comprehensive view so I'm not creating using a def variable(reqeust, id) function and my intention is to have both POST methods redirect back to the same page. How would I go about deleting a model record using a checkbox and POST? I will add an #login_required decorator later. Here is my code:
models.py:
class ReportDirectory(models.Model):
report_name = models.CharField(max_length=300, unique=True, blank=False)
report_desc = models.TextField()
report_type = models.CharField(max_length=300)
report_loc = models.TextField()
slug = models.SlugField(unique=True, max_length=300)
last_update = models.DateTimeField(null=True)
main_tags = models.CharField(max_length=300)
# Renames the item in the admin folder
def __str__(self):
return self.report_name
class Favorite(models.Model):
directory_user = models.ForeignKey(User, on_delete=models.CASCADE)
user_report = models.ForeignKey(ReportDirectory, on_delete=models.CASCADE)
favorited = models.BooleanField()
def __str__(self):
return str(self.directory_user)+" - "+str(self.user_report)
views.py:
from django.shortcuts import render,redirect
from django.views import generic
from .models import ReportDirectory, Favorite
from django.contrib.auth.models import User
from .forms import FavoriteForm
def report_directory(request):
favorite = Favorite.objects.filter(directory_user=request.user.id, favorited=True)
reports = ReportDirectory.objects.exclude(favorite__directory_user=request.user.id, favorite__favorited=True)
favform = FavoriteForm(initial={'directory_user':request.user,},)
context = {
'reports':reports,
'favorite':favorite,
'favform':favform
}
if request.method =='POST' and 'favorited' in request.POST:
form = FavoriteForm(request.POST)
if form.is_valid():
form.save()
return redirect('/report_directory')
else:
form = FavoriteForm()
elif request.method =='POST' and 'deletefav' in request.POST:
Favorite.objects.filter(id=id).delete()
return redirect('/report_directory')
return render(request, 'counter/report_directory.html',context)

Related

Django ownership assignment to modify or delete entries

First post here. I followed the project code in the Python Crash Course book, so if the code looks similiar that is why.
In my django project, I want all the users to be able to view everything on the website. However, I want to have only the users who entered information in the entries to be able to edit and delete said entries. I know I need to assign ownership, but I'm having difficulty assigning it. currently I have a default setting enabled. For some reason if I take out the default it messes everything up.
urls.py
"""Defines URL patterns for research_topic_database."""
# research_topic_database
from django.urls import path
from . import views
app_name = 'research_topic_database'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# Page that shows all the research category topics.
path('topics/', views.topics, name='topics'),
# Detail page for a single research entry submission.
path('topics/<int:topic_id>/', views.topic, name='topic'),
# Page for adding a new research entry submission.
path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
# Page for editing an entry.
path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
]
models.py
class Topic(models.Model):
"""A research category for topic submissions to fall under."""
category = models.CharField(max_length=19, choices=CATEGORY_CHOICES, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a string representation of the model."""
return self.category
class Entry(models.Model):
"""Entry information about a research topic."""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
classification = models.CharField(max_length=10, choices=CLASSIFICTION_CHOICES, blank=True)
# The research_title identifies the entry in the database.
research_title = models.CharField(max_length=200)
research_topic_description = models.CharField(max_length=200)
# Explain the USMC requirements you want the research to fulfill.
extended_topic_description = models.TextField()
desired_objectives = models.TextField()
sponsor = models.CharField(max_length=100)
point_of_contact = models.CharField(max_length=100)
mailing_address = models.CharField(max_length=200)
email_address = models.CharField(max_length=50)
phone = models.CharField(max_length=12)
fax = models.CharField(max_length=12)
desired_completion_date = models.CharField(max_length=12)
available_funding = models.CharField(max_length=50)
comments = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
# connecting research entries to certain Users.
owner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
# owner = models.ForeignKey(User, on_delete=models.CASCADE)
# owner = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""Return a string representation of the model."""
return f"{self.research_title[:100]}..."
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.http import Http404
from .models import Topic, Entry
from .forms import EntryForm
def index(request):
"""The home page for research_topic_database."""
return render(request, 'research_topic_database/index.html')
#login_required
def topics(request):
"""Show all research categories from TOPIC class."""
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'research_topic_database/topics.html', context)
#login_required
def topic(request, topic_id):
"""Show a single research category from TOPIC class
and all its submission entries."""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'research_topic_database/topic.html', context)
#login_required
def new_entry(request, topic_id):
"""Add a new entry submission under a research category."""
topic = Topic.objects.get(id=topic_id)
if request.method != 'POST':
# No data submitted; create a blank form.
form = EntryForm()
else:
# POST data submitted; process data.
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return redirect('research_topic_database:topic', topic_id=topic_id)
# Display a blank or invalid form
context = {'topic': topic, 'form': form}
return render(request, 'research_topic_database/new_entry.html', context)
#login_required
def edit_entry(request, entry_id):
"""Edit an existing research entry submission."""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method != 'POST':
# Initial request, pre-fill form with current entry.
form = EntryForm(instance=entry)
else:
# POST data submitted; process data.
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('research_topic_database:topic', topic_id=topic.id)
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'research_topic_database/edit_entry.html', context)

Django - Class Based View trouble How Combine DetailView with ListView in same template

can anyone tell me how combine detailview with list view and show info in the same template, i'll explain you, i'm learning Django and i am trying to create a Questions and Answer web app, and i need to show the question with all its awnsers, i need in my detailview for a specific question show below all it awsers, something like stackoverflow does
#models.py
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
# Create your models here.
class Question(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="question", null=True)
name = models.CharField(max_length=100)
description = models.TextField(max_length=100)
date = models.DateTimeField(auto_now_add=True)
cant_resp = models.IntegerField(default=0)
question_type = models.CharField(max_length=50, choices=QUESTION_TYPES_CHOICES)
def __str__(self):
return self.description
class Anwser(models.Model):
# user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="anwser", null=True)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.TextField(max_length=400)
date= models.DateTimeField(auto_now_add=True)
#and this are my views.py
from django.shortcuts import render, redirect
from django.urls import reverse, reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
from .forms import QuestionForm, AnwserForm
from .models import Question
# Create your views here.
class QuestionListView(LoginRequiredMixin, generic.ListView):
template_name = 'anwserquestions/question_list.html'
context_object_name = 'questions'
def get_queryset(self):
return Question.objects.all()
def createquestion(response):
if response.method == "POST":
print("Its POST method")
form = QuestionForm(response.POST)
# user =response.user
if form.is_valid():
name = form.cleaned_data["name"]
description=form.cleaned_data['description'],
question_type=form.cleaned_data['question_type'],
# date=form.cleaned_data['date'],
t = Question(name=name, description=description, question_type=question_type, cant_resp=0)
t.save()
response.user.question.add(t) # adds the to do list to the current logged in user
# return HttpResponseRedirect("/%i" %t.id)
return redirect('anwserquestions:question-list')
else:
form = QuestionForm()
return render(response, "anwserquestions/question_create.html", {"form":form})
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_queryset(self):
return Question.objects.all()
class QuestionDeleteView(LoginRequiredMixin, generic.DeleteView):
template_name = 'anwserquestions/question_delete.html'
context_object_name = 'question'
success_url = reverse_lazy('anwserquestions:question-delete')
# def get_queryset(self):
# return Question.objects.all()
You can get the related answers by including it in the views context, so you QuestionDetailView becomes
class QuestionDetailView(LoginRequiredMixin, generic.DetailView):
model = Question
template_name = 'anwserquestions/question_detail.html'
context_object_name = 'question'
def get_context_data(self, **kwargs):
context = super(QuestionDetailView, self).get_context_data(**kwargs)
context['answers'] = Answer.objects.filter(post=self.get_object())
return context

Django : Can't auto insert user ID into other form

I am trying to get user/customer info and copy it automatically to new model via custom form once requested but keep getting error. General overview as below.
(error : ValueError at /create_request/
Cannot assign "<SimpleLazyObject: <User: kambing>>": "OrderRequest.user" must be a "Customer" instance.)
model relationship between customer model and request model
my views.py as below:
from django.shortcuts import render, redirect
from .models import *
from accounts.models import *
from .forms import CreateRequestForm
from django.contrib.auth.decorators import login_required
from accounts.models import *
#login_required(login_url='login')
def createRequest(request):
form = CreateRequestForm()
if request.method =='POST':
form = CreateRequestForm(request.POST)
if form.is_valid():
order = form.save(commit=False)
order.user = request.user
order.save()
return redirect('/')
context = {'form':form}
return render(request, 'commerce_autoparts/request_form.html', context)
here my model.py(autopart_ecommerce): Same as shown in attached image
from django.db import models
from accounts.models import Customer
class Logistic(models.Model):
logistic_method = models.CharField(max_length=30, null=True,
blank=True)
def __str__(self):
return self.logistic_method
class OrderRequest(models.Model):
user = models.ForeignKey(Customer, on_delete=models.CASCADE,
null=True, blank=True)
ref_code = models.CharField(max_length=15, null=True, blank=True)
link = models.URLField(null=True, blank=True)
image = models.ImageField(upload_to='media/images',null=True,
blank=True)
price = models.FloatField(null=True)
draft = models.BooleanField(default=True)
logistic_method = models.ForeignKey(Logistic,
on_delete=models.CASCADE, null=True, blank=True)
note = models.TextField(max_length=100)
date_order = models.DateTimeField(auto_now=True)
I tried many solutions from stackoverflow but could not get it right. I am sorry if this not challenging question but I am stuck with this issue for some weeks. Some sort of guidance or reference available would be helpful.
I hope shared info is enough for your references.
Thank you
The problem is that it is a different model, so it doesn't like that. What you can do is copy the field data of the user to the customer, so you actually create new customer.
example:
# instead of this
order.user = request.user
order.save()
# you could do
new_user = Customer()
new_user.name = request.user.name
new_user.email = request.user.email
new_user.last_name = request.user.last_name
# then pass the user to the order
order.user = new_user
order.save()
I somehow manage to solve the issue. It was simply i don't refer the user to customer model. By adding the customer model (instance.user = request.user.customer), it automatically save the customer id once submitted. it may not be the perfect solution, but works for now..
#login_required(login_url='login')
def createRequest(request):
form = CreateRequestForm(request.POST)
if request.method =='POST':
form = CreateRequestForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user.customer
instance.ref_code = get_ref_code()
instance.save()
return redirect('/')

Django Model Terms of Service With Timestamp, Username, and Prompt User To Agree To Updated Terms of Service

I would like to create a model that contains a timestamp and the allauth currently logged in user who agreed to the Terms of Service. Then, on every page (if the user is logged in), annotate if the user has agreed to the latest Terms of Service (by comparing the timestamp of their last agreement to the timestamp of the latest updated Terms of Service), and if the user has not agreed to the most recent Terms of Service version they are redirected to a page that requires them to agree to the updated version. Then it redirects the user back to whence they came after they agree.
How does one go about creating something like this?
What I have so far is below.
Models.py:
from django.contrib.auth.models import User
class TermsOfService(models.Model):
agreement = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True,blank=True, null=True)
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.agreement
class UserMembership(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=40, unique=True)
membership = models.ForeignKey(
Membership, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.username
Forms.py:
from .models import TermsOfService
class TermsOfServiceForm(forms.ModelForm):
class Meta:
model = TermsOfService
fields = ('agreement',)
def __init__(self, *args, **kwargs):
super(TermsOfServiceForm, self).__init__(*args, **kwargs)
self.fields['agreement'].widget.attrs={ 'id': 'agreement_field', 'class': 'form-control', 'required': 'true', 'autocomplete':'off'}
App Urls.py:
from django.urls import path
from .views import ( terms_of_service_view )
app_name = 'app'
urlpatterns = [ path('terms_of_service_view/', terms_of_service_view, name='terms_of_service_view'), ]
Views.py:
def get_user_membership(request):
user_membership_qs = UserMembership.objects.filter(user=request.user)
if user_membership_qs.exists():
return user_membership_qs.first()
return None
def terms_of_service_view(request):
if request.method == 'POST':
form = TermsOfServiceForm(request.POST)
if form.is_valid():
user_membership = get_user_membership(request)
instance = form.save(commit=False)
instance.user = request.user
instance.save()
context = {
'user_membership': user_membership,
'form':form
}
return render(request, "index.html", context)
else:
form = TermsOfServiceForm()
context = {
'user_membership': user_membership,
'form': form,
}
return render(request, "index.html", context)
A question arises from your code, like how are you going to determine when user needs to agree to agreement, do you create a bunch of new entry in TermsOfService. Rather than that, why not create a new model named Terms and add it as ForeignKey.
class Term(models.Model):
text = models.TextField()
created_at = models.DateTimeField(auto_now_add=True,blank=True, null=True)
# blah blah
class TermsOfService(models.Model):
term = models.ForeignKey(Term, on_delete=models.DO_NOTHING)
agreement = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True,blank=True, null=True)
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
There is an advantage of taking this approach, that is all you need to do is create a new Term object, and rest can be taken care of by middleware. For example:
from django.urls import reverse
from django.shortcuts import redirect
class TermAgreeMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if not request.user.is_authenticated:
return response
term_date = Term.objects.last().created_at
user_term_date = request.user.termofservice_set.filter(created_at__gte=term_date).exists()
if not user_term_date:
return redirect(reverse('app:terms_of_service_view')+'?next='+request.path)
return response
And update the view:
def terms_of_service_view(request):
if request.method == 'POST':
form = TermsOfServiceForm(request.POST)
if form.is_valid():
user_membership = request.user.usermembership # you don't need another view as User has OneToOne relation with UserMembership
instance = form.save(commit=False)
instance.user = request.user
instance.term = Term.objects.last()
instance.save()
go_next = request.GET.get('next', None) # handle redirection
if go_next:
return redirect(go_next)
context = {
'user_membership': user_membership,
'form':form
}
return render(request, "index.html", context)
else:
form = TermsOfServiceForm()
context = {
'user_membership': user_membership,
'form': form,
}
return render(request, "index.html", context)
Finally add that TermAgreeMiddleware in MIDDLEWARE settings. So everytime you want users to agree a new term, just create a new Term instance(from admin site or shell).

Save modelForm to update existing record

I create a modelForm with instance to existing model (Book). I am not able to update the Books record. Adding a new record is fine but when I attempt to update, it appears to be unable to find the publisher (which is a foreign key). Error is "No Publisher matches the given query."
models.py
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __unicode__(self):
return self.name
class Meta:
ordering = ["name"]
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField(blank=True, verbose_name='e-mail')
objects = models.Manager()
sel_objects=AuthorManager()
def __unicode__(self):
return self.first_name+' '+ self.last_name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField(blank=True, null=True)
num_pages = models.IntegerField(blank=True, null=True)
class BookForm(ModelForm):
class Meta:
model = Book
views.py
def authorcontactupd(request,id):
if request.method == 'POST':
a=Author.objects.get(pk=int(id))
form = AuthorForm(request.POST, instance=a)
if form.is_valid():
form.save()
return HttpResponseRedirect('/contact/created')
else:
a=Author.objects.get(pk=int(id))
form = AuthorForm(instance=a)
return render_to_response('author_form.html', {'form': form})
error msg
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/books/bookupd/
No Publisher matches the given query.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
urls.py
from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from mysite10.books.views import about_pages, books_by_publisher, authorcontact,bookcontact, booklisting, authorcontactupd
from django.views.generic import list_detail
from mysite10.books.models import Publisher, Book
from django.contrib import admin
admin.autodiscover()
def get_books():
return Book.objects.all()
publisher_info = {
'queryset': Publisher.objects.all(),
'template_name':'books/publisher_publisher_list_page.html',
'template_object_name': 'publisher',
'extra_context': {'book_list': Book.objects.all},
}
book_info = {
'queryset': Book.objects.order_by('-publication_date'),
'template_name':'books/publisher_publisher_list_page.html',
'template_object_name': 'book',
'extra_context': {'publisher_list': Publisher.objects.all},
}
oreilly_books = {
'queryset': Book.objects.filter(publisher__name="O'Reilly"),
'template_name':'books/publisher_publisher_list_page.html',
'template_object_name': 'book',
'extra_context': {'publisher_list': Publisher.objects.all},
}
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
(r'^polls/', include('mysite10.polls.urls')),
(r'^search-form/$', 'mysite10.views.search_form'),
(r'^search/$', 'mysite10.views.search'),
(r'^contact/$', 'mysite10.contact.views.contact'),
(r'^contact/thanks2/(\d+)$', 'mysite10.contact.views.thanks2'),
(r'^contact/thanks/$', 'mysite10.contact.views.thanks'),
(r'^publishers/$', list_detail.object_list, publisher_info),
(r'^books/$', list_detail.object_list, book_info),
(r'^books/oreilly/$', list_detail.object_list, oreilly_books),
(r'^books/(\w+)/$', books_by_publisher),
(r'^author/$', authorcontact),
(r'^authorupd/(\d+)/$', authorcontactupd),
(r'^contact/created/$', 'mysite10.books.views.created'),
(r'^bookform/$', bookcontact),
(r'^contact/bookscreated/$', 'mysite10.books.views.books_created'),
(r'^booklist/$', 'mysite10.books.views.booklisting'),
(r'^books/bookupd/(\d+)$', 'mysite10.books.views.book_upd'),
)
-------------------------------------------------
I finally got it working with below codes.
error in urls.py because of missing forward slash before $.
Amended to (r'^books/bookupd/(\d+)/$'
views.py
def book_upd(request,id):
if request.method == 'POST':
a=Book.objects.get(pk=int(id))
form = BookForm(request.POST, instance=a)
if form.is_valid():
form.save()
return HttpResponseRedirect('/contact/bookscreated')
else:
a=Book.objects.get(pk=int(id))
form = BookForm(instance=a)
return render_to_response('book_form.html', {'form': form})
urls.py
(r'^books/bookupd/(\d+)/$', 'mysite10.books.views.book_upd'),
There's some missing information like what you have in your urls.py. Can you post it as well? Did you check in the database that the record was actually not updated? (the error might be a result of processing the redirect)
Your edit is not sufficient:
- did you check the databse to see if the record is updated?
- Please paste the entire urls.py as for example it is interesting to see what /contact/created is mapped to in case it did succeed, or whether you have some publisher.get() methods in it
In addition the traceback can also provide lots of useful information as to the source of the problem.
did you check if the object is updated in the database even though you get the error?
Can you try removing the "oreilly_books" section (or at least the queryset part) and try doing the same without it?