I am attempting to save simple data based on a button submission. But i keep getting following error:
TypeError at /exercise/1/
save() got an unexpected keyword argument 'commit'
models.py:
class StrategyHistory(models.Model):
user = models.ForeignKey(User)
strategy = models.ForeignKey(Strategies)
created = models.DateTimeField(editable=False)
modified = models.DateTimeField()
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = datetime.datetime.today()
self.modified = datetime.datetime.today()
return super(StrategyHistory, self).save(*args, **kwargs)
def __unicode__(self):
return self.strategy.name
views.py:
def exercise_view(request, pk):
template_name = 'mobileApp/page/exercise.html'
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('mobile_user_login'))
strategy = Strategies.objects.get(pk=pk)
context = {
'strategy':strategy,
}
if request.method == 'POST':
strategyhistory = StrategyHistory()
entry = strategyhistory.save(commit=False)
entry.user = self.request.user
entry.strategy = Strategies.objects.get(id=pk)
entry.save()
if pk < 5:
return HttpResponseRedirect(reverse('mobile_exercise', kwargs={'pk':pk+1}))
else:
return HttpResponseRedirect(reverse('mobile_comeback_later'))
return render_to_response(template_name,
context,
context_instance = RC( request, {} ))
html-file:
<form action="" method="post">{% csrf_token %}
Prøv igen
<button type="submit" value="submit" data-inline="true" data-transition="flow" data-icon="check" data-theme="b">Fortsæt</button>
</form>
I am running Django 1.6.2
Your view use StrategyHistory model incorrect. That is the use of forms. This is correct.
def exercise_view(request, pk):
template_name = 'mobileApp/page/exercise.html'
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('mobile_user_login'))
strategy = Strategies.objects.get(pk=pk)
context = {
'strategy':strategy,
}
if request.method == 'POST':
strategyhistory = StrategyHistory.objects.create(
user=request.user,
strategy=strategy)
if pk < 5:
return HttpResponseRedirect(reverse('mobile_exercise', kwargs={'pk': pk + 1}))
else:
return HttpResponseRedirect(reverse('mobile_comeback_later'))
return render_to_response(template_name,
context,
context_instance = RC( request, {} ))
Also you cannot use self.request in that view. There is no self declared.
May be this is what you want:
class StrategyHistory(models.Model):
user = models.ForeignKey(User)
strategy = models.ForeignKey(Strategies)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.strategy.name
Related
I am working in Django 3.2.13 trying to create a simple upload form for a file model with a chained foreign key. I have tried creating a form with a basic form model and a ModelForm, however, even when checking request.FILES there is no data and request_file = request.FILES['document'] if 'document' in request.FILES else Noneyields None.
views.py
def home(request):
if handleAuth(request) is not None:
return handleAuth(request)
user = request.user
if request.method == "POST":
# if the post request has a file under the input name 'document', then save the file.
form = FileSubmissionForm(user, request.POST, request.FILES)
#print(request.FILES)
#request_file = request.FILES['document'] if 'document' in request.FILES else None
#if request_file:
form.save()
#else:
# print("NO FILE")
userFiles = []
if user.is_company_admin:
temp = StorageFile.objects.filter(company_key=user.company_key)
else:
temp = StorageFile.objects.filter(company_key=user.company_key,
profile__in=user.user_profiles.all())
temp.order_by("profile")
for file in temp:
userFiles.append({"name": file.getFileName(), "path": file.getMediaPath()})
form = FileSubmissionForm(user)
return render(request=request,
template_name="fileCloudApp/home.html",
context={"userHasAdmin": user.is_company_admin, "files": userFiles, "form": form})
forms.py
from django import forms
from fileCloudApp.models import StorageFile
from loginApp.models import UserProfile
class FileSubmissionForm(forms.Form):
fileChoice = forms.FileField()
profileChoice = forms.ModelChoiceField(queryset=UserProfile.objects.none(), label="Choose profile")
def __init__(self, user, *args, **kwargs):
super(FileSubmissionForm, self).__init__(*args, **kwargs)
if user.is_company_admin:
temp = UserProfile.objects.filter(company_key=user.company_key)
else:
temp = user.user_profiles.all()
temp.order_by("label")
self.fields["profileChoice"].queryset = temp
self.user = user
def save(self):
print(self["fileChoice"].value()) # None
pro = UserProfile.objects.filter(id=int(self["profileChoice"].value()))
if len(pro) > 0:
pro = pro[0]
print(pro)
models.py
class StorageFile(models.Model):
date_updated = models.DateTimeField('Date Updated', default=timezone.now)
company_key = models.ForeignKey(CompanyModel, verbose_name="Company", on_delete=models.CASCADE)
file_upload = models.FileField(upload_to=company_directory_path)
profile = ChainedForeignKey(
UserProfile,
chained_field="company_key",
chained_model_field="company_key",
show_all=False,
auto_choose=True,
sort=True,
on_delete=models.PROTECT)
def getLocalPath(self):
return self.file_upload.name.split(str(self.company_key.id) + "/")[1]
def getMediaPath(self):
return "get/{0}/0/{1}".format(self.id, self.getFileName())
def getFileName(self):
return self.file_upload.name.split("/")[-1]
def getFilePath(self):
return settings.MEDIA_ROOT + "{0}/{1}".format(str(self.company_key.id), self.getFileName())
def __str__(self):
return str(self.company_key) + ": " + str(self.file_upload)
Form must contain enctype="multipart/form-data"
<form action="" method="post" enctype="multipart/form-data">
I am fairly new to Django and am following the try django 1.10 series by CodingEntrepreneurs on youtube and therefore, am unable to solve the problem. I am only seeing the submit button, while the input field is not showing. Below is the code that I am working on.
forms.py
from django import forms
class SubmitUrlForm(forms.Form):
url = forms.CharField(label="Submit Url")
views.py
from .forms import SubmitUrlForm
def home_view_fbv(request, *args, **kwargs):
if request.method == 'POST':
print(request.POST)
return render(request, "app/home.html", {})
class HomeView(View):
def get(self, request, *args, **kwargs):
the_form = SubmitUrlForm()
context = {
"title": "Submit Url",
"form": the_form
}
return render(request, "app/home.html", context)
def post(self, request, *args, **kwargs):
form = SubmitUrlForm(request.POST)
if form.is_valid():
print(form.cleaned_data)
return render(request, "app/home.html", {})
app/home.html
<div style= 'width: 800px; margin: 0 auto;'>
<h1> {{ title }} </h1>
<form method = 'POST' action = '.'> {% csrf_token %}
{{form.as_p}}
<input type= 'submit' value= 'Shorten' >
</form>
</div>
models.py
from django.db import models
from .utils import code_generator, create_shortcode
from django.conf import settings
SHORTCODE_MAX = getattr(settings, "SHORTCODE_MAX", 15)
class surlShortManager(models.Manager):
def all(self, *args,**kwargs):
qs_main = super(surlShortManager,self).all(*args, **kwargs)
qs = qs_main.filter(active = True)
return as
def refresh_shortcodes(self, items= 100):
qs = surlShort.objects.filter(id__gte = 1)
if items is not None and isinstance(items, int):
qs = qs.order_by('-id')[:items]
new_codes = 0
for q in qs:
q.shortcode = create_shortcode(q)
print(q.id)
q.save()
new_codes += 1
return "New codes made: {i}".format(i = new_codes)
class surlShort(models.Model):
url = models.CharField(max_length = 500)
shortcode = models.CharField(max_length = SHORTCODE_MAX, unique = True, null
= False, blank = True)
updated = models.DateTimeField(auto_now = True)
timestamp = models.DateTimeField(auto_now_add = True)
active = models.BooleanField(default = True)
objects = surlShortManager()
def save(self, *args, **kwargs):
if self.shortcode is None or self.shortcode == '':
self.shortcode = code_generator()
super(surlShort, self).save(*args, **kwargs)
def __str__(self):
return str(self.url)
Change your HomeView to this
from django.views import View
from django.http import HttpResponseRedirect
from .forms import SubmitUrlForm
class HomeView(View):
form_class = SubmitUrlForm
context = {
"title": "Submit Url",
"form": form_class
}
template_name = 'app/home.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
print(form.cleaned_data)
return HttpResponseRedirect('/success/')
return render(request, self.template_name, context)
I have two apps, here we will call them blog and comments.
Comments has a Comment model. Blog has a blog Model. Comments has a CommentForm. Blog has a DetailView.
I want my CommentForm to appear on by Blog DetailView, so people can submit comments from the blog detail page.
The form renders OK - it makes a POST request, it redirects to get_success_url() but (I've added a couple of prints to views.py - see below) in testing in views.py to see if the form data is received I see the form.is_valid() path is not met, and I don't understand why.
I'm essentially trying to follow this, the 'alternative better solution':
https://docs.djangoproject.com/en/2.2/topics/class-based-views/mixins/#using-formmixin-with-detailview
blog/views.py
class CommentLooker(SingleObjectMixin, FormView):
template_name = 'blogs/blog_detail.html'
form_class = CommentForm
model = blog
def get_object(self):
#self.team = get_object_or_404(team, team_id=self.kwargs['team_id'])
#queryset_list = blog.objects.filter(team = self.team)
team_id_ = self.kwargs.get("team_id")
blog_id_ = self.kwargs.get("blog_id")
return get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
return super(CommentLooker, self).post(request, *args, **kwargs)
def get_success_url(self):
return reverse('blogs:teams')
class blogDisplay(View):
def get(self,request,*args,**kwargs):
view = blogFromteamContentView.as_view()
return view(request, *args, **kwargs)
def post(self,request,*args,**kwargs):
view = CommentLooker.as_view()
return view(request,*args,**kwargs)
class blogFromteamContentView(LoginRequiredMixin, DetailView):
model = blog
template_name = 'blogs/blog_detail.html'
# override get_object so we can use blog_id when we use this class in urls.py
# otherwise DetailViews expect 'pk' which defaults to the primary key of the model.
def get_object(self):
team_id_ = self.kwargs.get("team_id")
blog_id_ = self.kwargs.get("blog_id")
return get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
def get_context_data(self, **kwargs):
context = super(blogFromteamContentView, self).get_context_data(**kwargs)
team_id_ = self.kwargs.get("team_id")
blog_id_ = self.kwargs.get("blog_id")
# get the list of blogs for a given blog id and team id combination.
context['queryset'] = get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
# get and set things related to ability to associate comments to a blog.
initial_data = {
"content_type": blog.get_content_type,
"object_id": blog.blog_id
}
comments = blog.comments # uses the #property set in this class.
comment_form = CommentForm(self.request.POST or None, initial=initial_data)
if comment_form.is_valid():
print(comment_form.cleaned_data)
else:
print('invalido!')
context['comment_form'] = comment_form
return context
blog/models.py
class Blog(models.Model):
team= models.ForeignKey(Team, on_delete=CASCADE)
blog_id = models.AutoField(primary_key=True)
blog_name = models.CharField(
max_length=100, verbose_name='Blog Name')
blog/urls.py
path('teams/<int:team_id>/blogs/<int:blog_id>/', blog.blogDisplay.as_view(), name='detail'),
blog_detail.html
<div>
<p class="lead"> Comments </p>
<form method="POST" action="."> {% csrf_token %}
{{ comment_form}}
<input type="submit" value="Post Comment" class="btn btn-primary">
</form>
<hr/>
{% for comment in blog.comments.all %}
<blockquote class="blockquote">
<p>{{ comment.content }}</p>
<footer class="blockquote-footer"> {{ comment.user }} | {{ comment.timestamp|timesince }} ago </footer>
</blockquote>
<hr/>
{% endfor %}
comments/forms.py
from django import forms
class CommentForm(forms.Form):
content_type = forms.CharField(widget=forms.HiddenInput)
object_id = forms.IntegerField(widget=forms.HiddenInput)
parent_id = forms.IntegerField(widget=forms.HiddenInput, required=False)
content = forms.CharField(widget=forms.Textarea)
edit:
after using print(comment_form.errors): object_idEnter a whole number.
suggesting my initial_data might be the problem. In fact both content_type and object_id in my initial_data were problems. I was asking for blog.blog_id - I.e. using the class, not an instance. So I changed
get_context_data:
def get_context_data(self, **kwargs):
context = super(blogFromteamContentView, self).get_context_data(**kwargs)
team_id_ = self.kwargs.get("team_id")
blog_id_ = self.kwargs.get("blog_id")
# get the list of blogs for a given blog id and team id combination.
context['queryset_list_recs'] = get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
instance = get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
initial_data = {
"content_type": instance.get_content_type,
"object_id": blog_id_
}
and to my views.py:
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
comment_form = CommentForm(self.request.POST)
if comment_form.is_valid():
print('valido')
c_type = comment_form.cleaned_data.get("content_type")
content_type = ContentType.objects.get(model=c_type)
obj_id = comment_form.cleaned_data.get('object_id')
content_data = comment_form.cleaned_data.get("content")
new_comment, created = Comment.objects.get_or_create(
user = self.request.user,
content_type = content_type,
object_id = obj_id,
content = content_data
)
else:
print('postinvalido!')
return super(CommentLooker, self).post(request, *args, **kwargs)
This (inappropriate print statements aside) now appears to give intended behaviour.
after using print(comment_form.errors):
object_id
List item
Enter a whole number.
suggesting my initial_data might be the problem. In fact both content_type and object_id in my initial_data were problems. I was asking for blog.blog_id - I.e. using the class, not an instance. So I changed
get_context_data:
def get_context_data(self, **kwargs):
context = super(blogFromteamContentView, self).get_context_data(**kwargs)
team_id_ = self.kwargs.get("team_id")
blog_id_ = self.kwargs.get("blog_id")
# get the list of blogs for a given blog id and team id combination.
context['queryset_list_recs'] = get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
instance = get_object_or_404(blog, blog_id=blog_id_, team=team_id_)
initial_data = {
"content_type": instance.get_content_type,
"object_id": blog_id_
}
and to my views.py:
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
comment_form = CommentForm(self.request.POST)
if comment_form.is_valid():
print('valido')
c_type = comment_form.cleaned_data.get("content_type")
content_type = ContentType.objects.get(model=c_type)
obj_id = comment_form.cleaned_data.get('object_id')
content_data = comment_form.cleaned_data.get("content")
new_comment, created = Comment.objects.get_or_create(
user = self.request.user,
content_type = content_type,
object_id = obj_id,
content = content_data
)
else:
print('postinvalido!')
return super(CommentLooker, self).post(request, *args, **kwargs)
This (inappropriate print statements aside) now appears to give intended behaviour. I'm unclear why an instance of CommentForm needs to be created inside the post method - it feels like I'm doing something wrong here.
im only student so please bear with me. I already posted another topic about this but in function view. now i want to how do i convert this try exception to a class view and also add that comment form.
here's my views.py def
def BookDetail(request, id):
most_recent = Book.objects.order_by('-timestamp')[:3]
book= get_object_or_404(Book, id=id)
form = CommentForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form.instance.user = request.user
form.instance.post = book
form.save()
return redirect(reverse("book-detail", kwargs={
'id': book.pk
}))
if request.user.is_anonymous:
user_membership = None
else:
try:
user_membership = Customer.objects.get(user=request.user)
except Customer.DoesNotExist:
user_membership = None
context = {
'user_membership': user_membership,
'form': form,
'book': book,
'most_recent': most_recent,
}
return render(request, 'catalog/book_detail.html', context)
here is my new class view
class BookDetailView(NeverCacheMixin, generic.DetailView):
model = Book
UPDATE POST
here's my models.py..
class Book(models.Model):
slug = models.SlugField(unique=True, help_text="Enter BIC Code", null=True)
title = models.CharField(max_length=200) #more fields after this
timestamp = models.DateTimeField(default=timezone.now)
activeReference = models.ManyToManyField(Membership)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book-detail', kwargs={'slug': self.slug})
#property
def get_comments(self):
return self.comments.all().order_by('-timestamp')
#property
def pages(self):
return self.page_set.all()
class Page(models.Model):
slug = models.SlugField(max_length=50)
book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
preview = models.FileField(upload_to='book_content', validators=[pdf_file_extension], help_text="PDF File Only")
def __str__(self):
return self.slug
def get_absolute_url(self):
return reverse('page-detail',
kwargs={
'book_slug': self.book.slug,
'page_slug': self.slug
})
here's my URL pattern
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='book-list'),
path('book-detail/<slug>', views.BookDetailView.as_view(), name='book-detail'),
path('book-detail/<book_slug>/<page_slug>', views.PageDetailView.as_view(), name='page-detail'),
path('search/', views.Search, name='search'),
]
and my book_detail.html
{% for content in book.pages %}
Read
{% endfor %}
{% else %}
CBV are good when you need inheritance or need to deal with different HTTP methods to have the same route. If that is not the case, a FBV is a better choice. That being said, for what you are trying to do, you should just a FormView that will handle everything about a post and forms.
Something like:
class BookViewSet(FormView):
form = CommentForm
template_name = 'catalog/book_detail.html'
def form_valid(self, form):
self.send_mail(form.cleaned_data)
return super(BookViewSet, self).form_valid(form)
If you are handling forms, you should be using CreateView or FormView not DetailView. Here is an implementation example, as you can see is a little complex for someone new to Django:
from django.views.generic import CreateView
class BookDetailView(NeverCacheMixin, CreateView):
form_class = CommentForm
template_name = 'catalog/book_detail.html'
def dispatch(self, request, *args, **kwargs):
book_slug = self.kwargs.get('slug') # url variables are stored in self.kwargs
self.book = get_object_or_404(Book, slug=book_slug) # attach book to your view
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
# context data passed to template
kwargs['book'] = self.book
kwargs['most_recent'] = Book.objects.order_by('-timestamp')[:3]
if request.user.is_anonymous:
user_membership = None
else:
try:
user_membership = Customer.objects.get(user=self.request.user)
except Customer.DoesNotExist:
user_membership = None
kwargs['user_membership'] = user_membership
return super().get_context_data(**kwargs)
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
instance.post = self.book
instance.save()
return redirect(self.book.get_absolute_url())
My Django 2 app using Django Channels has a ThreadView or a page that displays a messaging thread between two users, with URL
re_path(r"^(?P<username>[\w.#+-]+)", chat_views.ThreadView.as_view(), name='thread'),
There is a text input form at the bottom of the page to submit a new message via request.POST which is handled via the ThreadView.
I think the problem is arising when I try to put a request.POST delete form (DeleteView) on the page as well in order to delete the thread, URL
path('<int:pk>/delete/', chat_views.ThreadDeleteView.as_view(), name='thread_delete'),
When the delete form is submitted, I get the error
DoesNotExist at /messages/2/delete/ User matching query does not exist.
With these lines being cited at causing the error (from views.py and models.py)
self.object = self.get_object()
obj, created = Thread.objects.get_or_new(self.request.user, other_username)
user2 = Klass.objects.get(username=other_username)
The first line comes from the def post function on the ThreadView, and I'm not sure why that's being triggered.
The thread isn't being deleted as when I go back to inbox, it's still there.
I'm a beginner and may be getting this totally wrong so would appreciate any feedback.
views.py
class InboxView(LoginRequiredMixin, ListView):
template_name = 'chat/inbox.html'
context_object_name = 'threads'
def get_queryset(self):
return Thread.objects.by_user(self.request.user).exclude(chatmessage__isnull=True).order_by('-timestamp')
class ThreadView(LoginRequiredMixin, FormMixin, DetailView):
template_name = 'chat/thread.html'
form_class = ComposeForm
success_url = '#'
def get_queryset(self):
return Thread.objects.by_user(self.request.user)
def get_object(self):
other_username = self.kwargs.get("username")
obj, created = Thread.objects.get_or_new(self.request.user, other_username)
if obj == None:
raise Http404
return obj
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
thread = self.get_object()
user = self.request.user
message = form.cleaned_data.get("message")
ChatMessage.objects.create(user=user, thread=thread, message=message)
return super().form_valid(form)
class ThreadDeleteView(DeleteView):
model = Thread
success_url = reverse_lazy('chat:inbox')
models.py
class ThreadManager(models.Manager):
def by_user(self, user):
qlookup = Q(first=user) | Q(second=user)
qlookup2 = Q(first=user) & Q(second=user)
qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
return qs
# method to grab the thread for the 2 users
def get_or_new(self, user, other_username): # get_or_create
username = user.username
if username == other_username:
print(other_username)
return None, None
# looks based off of either username
qlookup1 = Q(first__username=username) & Q(second__username=other_username)
qlookup2 = Q(first__username=other_username) & Q(second__username=username)
qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
if qs.count() == 1:
return qs.first(), False
elif qs.count() > 1:
return qs.order_by('timestamp').first(), False
else:
Klass = user.__class__
user2 = Klass.objects.get(username=other_username)
if user != user2:
obj = self.model(
first=user,
second=user2
)
obj.save()
return obj, True
return None, False
class Thread(models.Model):
first = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
second = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = ThreadManager()
def __str__(self):
return f'{self.id}'
#property
def room_group_name(self):
return f'chat_{self.id}'
def broadcast(self, msg=None):
if msg is not None:
broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
return True
return False
thread html page
<!-- Delete Thread -->
<form action="{% url 'chat:thread_delete' thread.id %}" method='POST'>
{% csrf_token %}
<button type='submit' class='btn btn-light' value='delete'>
<i class="fas fa-trash-alt" style="color:royalblue">
</i>
</button>
</form>
<!-- text input / write message form -->
<form id='form' method='POST'>
{% csrf_token %}
<input type='hidden' id='myUsername' value='{{ user.username }}' />
{{ form.as_p }}
<center><button type="submit" class='btn btn-success disabled' value="Send">Send</button></center>
</form>
urls.py
app_name = 'chat'
urlpatterns = [
path('', chat_views.InboxView.as_view(), name='inbox'),
re_path(r"^(?P<username>[\w.#+-]+)", chat_views.ThreadView.as_view(), name='thread'),
path('<int:pk>/delete/', chat_views.ThreadDeleteView.as_view(), name='thread_delete'),