I am creating an image upload function with django.
However, it is not uploaded.
I don't know the code mistake, so I want to tell you.
I tried variously, but if I specify default for imagefiled,
default will be applied.
#form
class RecordCreateForm(BaseModelForm):
class Meta:
model = URC
fields = ('image','UPRC','URN',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordCreateForm,self).__init__(*args, **kwargs)
self.fields['URN'].queryset = UPRM.objects.filter(user=user)
#view
class RecordCreate(CreateView):
model = URC
form_class = RecordCreateForm
template_name = 'records/urcform.html'
success_url = reverse_lazy('person:home')
def get_form_kwargs(self):
kwargs = super(RecordCreate, self).get_form_kwargs()
# get users, note: you can access request using: self.request
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
user = self.request.user
form.instance.user = user
form.instance.group = belong.objects.get(user=user).group
return super().form_valid(form)
#model
def get_upload_path(instance, filename):
n = datetime.now()
prefix = "records/"
ymd='/'.join([n.strftime('%Y'), n.strftime('%m'), n.strftime('%d'), ""]) + "/"
directory=str(instance.user.id) + "/"
name=str(uuid.uuid4()).replace("-", "")
extension=os.path.splitext(filename)[-1]
return ''.join([prefix, directory, ymd, name, extension])
class URC(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(group, on_delete=models.CASCADE, null=True)
URN = models.ForeignKey(UPRM, on_delete=models.CASCADE)
UPRC = models.CharField(max_length=300)
image = models.ImageField(upload_to=get_upload_path)
def __str__(self):
return self.UPRC
#urls
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I will post any other necessary code.
Sorry for the poor English.
Postscript
The page is redirected without any error display.
But admin screen was able to upload.
class BaseModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(BaseModelForm, self).__init__(*args, **kwargs)
#template
<form method="post" action="">
{% csrf_token %}
{{form.image.label_tag}}
{{form.image}}
{{form.UPRC.label_tag}}
{{form.UPRC}}
{{form.URN.label_tag}}
{{form.URN}}
<input class="btn btn-primary" type="submit" value="submit">
</form>
Your <form> tag misses the enctype, as explained here:
<form method="post" enctype="multipart/form-data">
You can take a look at this example.
https://www.pythonsetup.com/simple-file-uploads-django-generic-createview/
def form_valid(self, form):
self.object = Author(photo=self.get_form_kwargs().get('files')['photo'])
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
Related
can you help me?
I can't fix problem: my don't show error validation
when I write not unique slug at form -> no error at form
I think problem at use def post() or return redirect after validations form.
I try many different solutions but nothing helps.
Maybe you should use a non-standard way to report an error?
models.py
class ShortUrl(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Автор URL', null=True)
url = models.CharField('Ссылка', max_length=200)
slug = models.SlugField('Короткое имя ссылки', unique=True, max_length=20)
def __str__(self):
#return self.slug
return f"Короткая ссылка: {self.user} >> {self.slug}"
class Meta:
verbose_name = 'Ссылка'
verbose_name_plural = 'Ссылки
forms.py
class ShortURLForm(forms.ModelForm):
slug = forms.SlugField(
label='Название URL',
required=True,
widget=forms.TextInput(attrs={'placeholder': 'Укажите уникальный URL'})
)
url = forms.CharField(
label='Ссылка',
required=True,
widget=forms.TextInput(attrs={'placeholder': 'Ссылка которую нужно сократить'})
)
class Meta:
model = ShortUrl
fields = ['user', 'url', 'slug']
widgets = {'user': forms.HiddenInput()}
views.py
class ShortURLPage(LoginRequiredMixin, ListView):
model = ShortUrl
template_name = 'main/shorts.html'
context_object_name = 'shorts'
def get_context_data(self, *, object_list=None, **kwargs):
ctx = super(ShortURLPage, self).get_context_data(**kwargs)
ctx['form'] = ShortURLForm()
userurls = ShortUrl.objects.filter(user=self.request.user)
ctx['shorts'] = userurls
ctx['title'] = 'Добавление ссылок'
return ctx
def post(self, request, *args, **kwargs):
post = request.POST.copy()
post['user'] = request.user
request.POST = post
form = ShortURLForm(request.POST)
if form.is_valid():
slug = form.cleaned_data['slug']
url = form.cleaned_data['url']
form.save()
return redirect('shorts')
shorts.html
<form method="post" class="form">
{% csrf_token %}
{{ form }}
<button class="button" type="submit">Создать ссылку</button>
</form>
urls.py
urlpatterns = [
path('', views.homepage, name='home'),
path('about/', views.about, name='about'),
path('shorts/', views.ShortURLPage.as_view(), name='shorts'),
path('shorts/<str:slug>/', views.urlRedirect, name='redirect'),
]
Ok, you're not so far away with accomplishing what you want.
Generally your post method should look like this:
def post(self, request, *args, **kwargs):
post = request.POST.copy()
post['user'] = request.user
request.POST = post
form = ShortURLForm(request.POST)
if form.is_valid():
slug = form.cleaned_data['slug']
url = form.cleaned_data['url']
form.save()
else:
context = {
'form': form,
}
return render(
request,
self.template_name,
context,
)
return redirect('shorts')
Then, you should write your shorts.html template like this:
<form method="post" class="form">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.errors }}
{{ form }}
<button class="button" type="submit">Создать ссылку</button>
</form>
I am trying to make a form that is dynamically selected by a DetailView object.
I want to click the DetailView link and be taken to a form whose primary key is the same as the primary key from my detail view. When I attempt to do this I get an error. How can I do this? Is their a prebuilt library that will assist me?
My Model:
'''
class MemberStudent(models.Model):
instructor = models.ForeignKey(Teachers, on_delete=models.CASCADE)
name = models.CharField(max_length=50, default="Doe")
age = models.IntegerField(default=99)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('student_detail', args=[str(self.id)])
class BehaviorGrade(models.Model):
SEVERITY = [
('Bad','Bad Behavior'),
('Good','Good Behavior'),
('Danger','Dangerous'),
]
LETTER_GRADE = [
('A','A'),
('B','B'),
('F','F'),
]
studentName = models.ForeignKey(MemberStudent, on_delete=models.CASCADE) #need a link to student name
eventGrade = models.CharField(max_length=1, choices=LETTER_GRADE)
eventSeverity = models.CharField(max_length=15, choices=SEVERITY)
eventTitle = models.CharField(max_length=15)
eventDescription = models.TextField()
def __str__(self):
return self.eventTitle
'''
My Views:
'''
class StudentDetailView(FormMixin,DetailView):
model = MemberStudent
template_name = 'student_detail.html'
form_class = BehaviorForm
def get_success_url(self):
return reverse('student_detail', kwargs={'pk':self.object.pk})
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
form.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
return super().form_valid(form)
'''
my forms.py:
'''
class BehaviorForm(ModelForm):
class Meta:
model = BehaviorGrade
fields = ['eventGrade',
'eventSeverity','eventTitle',
'eventDescription']
'''
my url:
'''
path('students/<int:pk>', StudentDetailView.as_view(), name='student_detail'),
'''
my htmltemplate(its a detailview with a form below on the same page):
'''
{{ object.id }}
{{ object.name }}
{{ object.age }}
{{ object.instructor }}
<form action="{% url 'student_detail' object.id %}" method="POST">
{{ form }}
{% csrf_token %}
<input type="submit" value="REVIEW">
</form>
'''
error message when form submitted:
"IntegrityError at /student/students/1
NOT NULL constraint failed: Students_behaviorgrade.studentName_id"
The form also is sent without the PK I have requested in my form code.
the django error log shows the PK is never sent
here is the log message on a test of dummy data:
params [None, 'A', 'Bad', 'asdf', 'asdf']
That's because you have to manually set the member student id on the behavior garde.
You can do it like this in the post function of your view :
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
behavior_grade = form.save(commit=False)
behavior_grade.studentName = self.object
return self.form_valid(form)
else:
return self.form_invalid(form)
You can also take a look at this method to use the form_valid function to do it :
## Include the instance object before saving
def form_valid(self, form):
form.instance.studentName = self.object
return super().form_valid(form)
The solution was to to call the primary key in the model method. Then to save to the correct model object I called .pk on my object. I'm cannot elegantly explain this solution however upon testing several different scenarios it works.
'''
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
behavior_grade = form.save(commit=False)
behavior_grade.studentName = self.object #passes unamed form field
behavior_grade.studentName.pk = form.save(commit=True) #calls key
return self.form_valid(form)
else:
return self.form_invalid(form)
'''
I started learning Django about a month ago and just finished Django for Beginners by William Vincent. The book ends with Ch.15: Comments and shows how the admin can add comments to posts.
Q: Can someone, please, show me or point me in the right direction as to how I can let registered users also add comments to posts? Is there perhaps a 3rd party app for that?
What I have so far:
Models:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='images/', null=True, blank=True, height_field=None, width_field=None)
upload = models.FileField(upload_to='files/', null=True, blank=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comment')
comment = models.CharField(max_length=140)
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(), on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'body', 'image', 'upload')
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('comment', 'author')
Views:
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
comment_form = CommentForm
login_url = 'login'
class ArticleDetailView(LoginRequiredMixin, DetailView):
model = Article
template_name = 'article_detail.html'
login_url = 'login'
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ('title', 'body', 'image', 'upload')
template_name = 'article_edit.html'
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
form_class = PostForm
template_name = 'article_new.html'
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
URLs:
urlpatterns = [
path('<int:pk>/edit/', ArticleUpdateView.as_view(), name='article_edit'),
path('<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),
path('<int:pk>/delete/', ArticleDeleteView.as_view(), name='article_delete'),
path('', ArticleListView.as_view(), name='article_list'),
path('new/', ArticleCreateView.as_view(), name='article_new'),]
Thank you for your attention.
Solved. In my views.py I added the following function:
def add_comment(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.article = article
comment.save()
return redirect('article_detail', pk=article.pk)
else:
form = CommentForm()
return render(request, 'add_comment.html', {'form': form})
Then the following .html file was added to templates:
add_comment.html
{% extends 'base.html' %}
{% block content %}
<h4>Add a Comment</h4>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock content %}
P.S.: Initially I was getting an ImportError: cannot import name 'add_comment' from 'articles.views'.
I thought it was a circular import problem and what worked for me was just getting the def add_comment indentation right.
I would like to filter through the restaurants that the request.user has done. following the docs but i keep getting __init__() got an unexpected keyword argument user when I try to filter
forms.py
from .models import Restaurant
from .models import Item
from django import forms
class LocationCreate(forms.ModelForm):
class Meta:
model = Item
fields = [
'restaurant'
'category',
'food_name'
]
def __init__(self, user=None, *args, **kwargs):
super(ItemCreate, self).__init__(*args, **kwargs)
self.fields['restaurant'].queryset = Restaurant.objects.filter(owner=user)
models.py
class Restaurant(models.Model):
restaurant_name = models.CharField(max_length=250)
restaurant_photo = models.ImageField(upload_to='roote_image')
category = models.ManyToManyField(Category)
timestamp = models.DateTimeField(auto_now_add=True, null=True)
updated = models.DateTimeField(auto_now=True, null=True)
owner = models.ForeignKey(User)
def get_absolute_url(self):
return reverse('post:detail', kwargs={'pk': self.pk})
class Item(models.Model):
restaurant= models.ForeignKey(Roote, on_delete=models.CASCADE, null=True)
food_name = models.CharField(max_length=1000)
category = models.CharField(max_length=250)
owner = models.ForeignKey(User)
def __str__(self):
return self.food_name
def get_absolute_url(self):
return reverse('post:detail', kwargs={'pk': self.pk})
views.py
class ItemCreate(CreateView):
model = Item
fields = ['restaurant','category ', 'food_name ']
success_url = reverse_lazy('post:index')
def form_valid(self, form):
if form.is_valid():
roote = restaurant.objects.filter(owner =self.request.user)
instance = form.save(commit=False)
instance.owner = self.request.user
return super(ItemCreate, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(ItemCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
detail.html
{% block body %}
<div class="col-sm-6 col-sm-offset-3">
<img src="{{ restaurant.restaurant_photo.url }}" style="width: 250px;" >
<h1>{{ restaurant.restaurant_name }}</h1>
{% for item in restaurant.item_set.all %}
{{ item.food_name }}: {{ item.category}}
<br>
{% endfor %}
The form works without the filter but it brings in every instance of a restaurant that has been made in the web site
full error:
return form_class(**self.get_form_kwargs())
TypeError: __init__() got an unexpected keyword argument 'user'
You forgot to add form_class attribute to your view
class ItemCreate(CreateView):
model = Item
success_url = reverse_lazy('post:index')
form_class = LocationCreate # <- here
def form_valid(self, form):
if form.is_valid():
roote = restaurant.objects.filter(owner=self.request.user)
instance = form.save(commit=False)
instance.owner = self.request.user
return super(ItemCreate, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(ItemCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
According to the docs, this is the signature of the __init__ method for a ModelForm:
def __init__(self, *args, **kwargs)
See that there is no user? This is what the error message is telling you.
If you want to get the user, try via self.request.user (or something similiar, depending on what middlewares you use).
Hope that helps!
I'm having trouble with adding comments to class based views,
forms.py:
class RequestForm(ModelForm):
class Meta:
model = Request
exclude = ('slug',)
class RequestCommentForm(ModelForm):
class Meta:
model = RequestComment
fields = ['body' ]
models.py:
class Request(models.Model):
title = models.CharField(max_length=250 )
date = models.DateTimeField('Request date', default=timezone.now, editable=False )
department = models.CharField(max_length=2, choices=DEPARTMENT)
support_request = models.TextField('Request', max_length=2500, blank=True)
owner = models.ForeignKey(User,)
slug = models.SlugField(blank=True, editable=False)
def __unicode__(self):
return self.title
views.py:
class RequestDetailView(ModelFormMixin, DetailView):
model = Request
form_class = RequestCommentForm
def get_success_url(self):
return reverse('request-detail', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(RequestDetailView, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def post(self, request, *args, **kwargs):
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):
form.instance.author = self.request.user
form.instance.request = Request.objects.get(pk=self.object.pk)
form.instance.created = timezone.now
form.save()
Also tried this part with:
self.object = form.save(commit=False)
self.object.author = self.request.user
self.object.request = Request.objects.get(pk=self.object.pk)
self.object.created = timezone.now
self.object.save()
return super(RequestDetailView, self).form_valid(form)
template: request_detail.html comments section .....
{% load bootstrap %}
<form action="{% url 'request-detail' object.id %}" method="post"> {% csrf_token %}
<ul class="form-group">
{{ form|bootstrap }}
</ul>
<input class="btn btn-primary" type="submit" value="Submit" />
</form>
.....
Page renders correctly, but when I submit, no-go with saving comment.
Debug toolbar shows that sql queries are updating the request model, instead of request comment.
Can't figure out how to add simple comment form from different model to detail page.
Any help would be appreciated.
Also, if there is more elegant way off adding comments form to class based view, would love to see it. My google-fu didn't help me to find anything.
I know I'm answering this too late, but maybe someone with the same question, in the future, may benefit.
Class RequestDetailView(DetailView):
model = Request
template_name = 'detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context ['comment'] = RequestComment.objects. all()
context['form'] = RequestCommentForm()
return context
Class CommentCreateView(CreateView):
model = RequestComment
form_class = RequestCommentForm
def get_success_URL(self):
return reverse ('request: detail', kwargs = {'slug':self.object.post.slug})
def form_valid(self, form):
post = get_object_or_404(Request, slug = self.kwargs ['slug'])
Form.instance.post = Request
return super().form_valid(form)
The URL
path('<slug:slug>/add_comment/', CommentCreateView.as_view(), name = add_comment')
And finally the HTML
<form action="{% url 'request:add_comment' request.slug %}" enctype = "multiparty/form-data" method = "post">
</form>
And that's it. I answered using my phone so there's some typos etc. This is my first answer here, I searched stack overflow for answers I'll post links later. I assumed RequestComment foreignkey field is post and creating models with name 'request' is not encouraged in Django.
Wish I could find a way to do this with CBV, but nope.. function view works great...
class RequestDetailView(ModelFormMixin, DetailView):
model = Request
form_class = RequestCommentForm
def get_success_url(self):
return reverse('request-detail', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(RequestDetailView, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def comments(self):
return RequestComment.objects.filter(request=Request.objects.get(pk=self.object.pk))
def RequestCommentAddView(request, pk):
form = RequestCommentForm(request.POST or None)
if form.is_valid() and pk:
form.instance.author = request.user
form.instance.request = Request.objects.get(pk=pk)
form.save()
return HttpResponseRedirect(reverse('request-detail', kwargs={'pk': pk}))
return HttpResponseRedirect(reverse('request-detail', kwargs={'pk': pk}))