How to handle data from two forms in one view? - python

So I have two forms.ModelForm for my two models
First:
class TranslatorChoice(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_id = kwargs.pop('user_id',None)
super(TranslatorChoice, self).__init__(*args, **kwargs)
self.fields['owner'].queryset = Translator.objects.all().filter(owner_id = self.user_id)
owner = forms.ModelChoiceField(queryset = None)
class Meta:
model = Translator
fields = ('owner',)
Second:
class ProfileChoice(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_id = kwargs.pop('user_id',None)
super(ProfileChoice, self).__init__(*args, **kwargs)
self.fields['login'].queryset = Profile.objects.all().filter(created_by_id = self.user_id)
login = forms.ModelChoiceField(queryset= None, label='Profile')
class Meta:
model = Profile
fields = ('login',)
I've tried writing a view for them but it doesn't work, seems like it just won't save because whenever I hit submit button it just refreshes the page and cleans the fields without redirecting me to needed URL. The model instances in my DB aren't updated either.
Here's the view:
def link_profile(request):
context = {
'form': ProfileChoice(user_id=request.user.id),
'form2': TranslatorChoice(user_id=request.user.id)
}
if request.method == 'POST':
form = ProfileChoice(request.POST)
form2 = TranslatorChoice(request.POST)
if form.is_valid():
login = form.cleaned_data.get('login')
translator = form.cleaned_data.get('owner')
link = Profile.objects.get(login=login)
link.owner = login
link.save(['owner'])
form.save()
form2.save()
return redirect('dashboard')
return render(request, 'registration/link.html', context)
I know also something is wrong is because I am using to many save functions. I just don't have any experience in creating views like that...
Sharing my template:
{% extends 'base.html' %}
{% block content %}
<h2>Add profile</h2>
<form method="post">
{% csrf_token %}
<table>
{{ form.as_table }} {{ form2.as_table }}
</table>
<button type="submit">Link</button>
</form>
{% endblock %}`
And my urls.py part with the view:
url(r'^link/', views.link_profile),

You didn't share your urls.py or the form in your template so it's not clear if the view is being executed, or how you're passing your forms. But, here's something that might work if you're not doing it already.
{{ form.as_table }}
{{ form2.as_table }}
FYI: there are some indentation issues with your code but I'm assuming that that's just something that happened when you pasted it here.

Related

Django - TypeError __init__() missing 1 required positional argument when uploading a file

I want to set an initial value "test" to the field name when I'm uploading a file with a Django. Here is what I tried in views.py:
class UploadFile(CreateView):
form_class = UploadFileForm
template_name = "tool/upload.html"
success_url = reverse_lazy('tool:index')
fields = ['file',]
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect(self.success_url)
else:
return render(request, self.template_name, {'form': form})
And in forms.py:
class UploadFileForm(forms.ModelForm):
class Meta:
model = CheckFile
fields = ['file', ]
def __init__(self, file, *args, **kwargs):
file = kwargs.pop('file')
super(UploadFileForm, self).__init__(*args, **kwargs)
if file:
self.fields['name'] = "test"
But I end up having the following error: TypeError: UploadFileForm.__init__() missing 1 required positional argument: 'file'
I don't understand why I keep having this error. Could you please help me?
Thanks!
Edit : here's the HTML form.
{% extends 'base.html' %}
{% block content %}
<h1>Enregistrer les tarifs</h1>
<form method="POST">
<p>
{% csrf_token %}
{{ form.as_p }}
</p>
<button type="submit">Save</button>
</form>
{% endblock %}
You are doing too much, the file = kwargs.pop('file') makes no sense: the data is passed as request.FILES and is passed to the ModelForm, your ModelForm can thus look like:
class UploadFileForm(forms.ModelForm):
class Meta:
model = CheckFile
fields = ['file', ]
# no __init__
The same for your view: Django will automatically create the form and pass the data accordingly. If you want to specify the name of the CheckFile, you can do that in the form_valid method:
class UploadFileView(CreateView):
form_class = UploadFileForm
template_name = "tool/upload.html"
success_url = reverse_lazy('tool:index')
def form_valid(self, form):
form.instance.name = 'test'
return super().form_valid(form)
If you are submitting files, you should specify enctype="multipart/form-data":
<form method="POST" enctype="multipart/form-data">
<p>
{% csrf_token %}
{{ form.as_p }}
</p>
<button type="submit">Save</button>
</form>
and that's all that is necessary.

How to get user object using username in django template

I am trying to get user's profile picture in a template using their username. What I have tried:
templatetags/users_extras.py:
from django import template
from django.contrib.auth.models import User
register = template.Library()
#register.filter(name="get_user", is_safe=True)
def get_user(username):
return User.objects.filter(username=username).first()
My template:
{% load users_extras %}
<img src="{{ username|get_user.profile.image.url }}">
My Profile view:
class Profile(ListView):
model = Post
template_name = "users/profile.html"
context_object_name = 'posts'
ordering = ['-datePosted']
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-datePosted')
def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['username'] = self.kwargs['username']
return context
The url for profile page is like path('profile/<str:username>/', Profile.as_view(), name='profile')
But that gives error
Could not parse the remainder: '.profile.image.url' from 'username|get_user.profile.image.url'
How can I fix this error or how can I get user object using username in django template?
You may need to get the result of the filter in a variable.
{% load users_extras %}
{% with username|get_user as user %}
<img src="{{ user.profile.image.url }}">
{% endwith %}
No need for solving things in template. First it is a bad practive. Second there's a better way. Just edit the function get_context_data
def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['user_requested'] = get_object_or_404(User,
username=self.kwargs.get('username'))
return context

Edit form in django doesn't save record after update

I have a little problem I've create a edit form to update the existing records. The form is displaying correctly, but when I click the edit button to update the records, the url redirecting me and record is not updated.
My views.py resposible for edit:
#login_required
def szczegoly_pracownik(request, id):
link_pracownik = get_object_or_404(Cudzoziemiec, id=id)
return render(request, 'cudzoziemiec/szczegoly_pracownik.html', {'link_pracownik': link_pracownik})
#login_required
def edycja_pracownika(request, id):
link_pracownik = get_object_or_404(Cudzoziemiec, id=id)
if request.method == 'POST':
edycja_pracownika = CudzoziemiecForm(request.POST, instance=link_pracownik)
if edycja_pracownika.is_valid():
link_pracownik = edycja_pracownika.save(commit=False)
link_pracownik.save()
return render('szczegoly_pracownik', id=link_pracownik.id)
else:
edycja_pracownika = CudzoziemiecForm(request.user, instance=link_pracownik)
return render(request, 'cudzoziemiec/edycja_pracownika.html', {'edycja_pracownika': edycja_pracownika})
The def szczegoly_pracownika is responsible for displaying the detail view
File edycja_pracownika.html
{% if request.user.is_authenticated %}
<form action="." method="post">
{{ edycja_pracownika.as_p }}
{% csrf_token %}
<div class="float-right">
<p><input type="submit" value="Edytuj" ></p>
{% endif %}
and the urls.py responsible for detail view and edit view
...
path('pracownik/<id>', edycja_pracownika, name='edycja_pracownika'),
path('pracownik/<id>/', szczegoly_pracownik, name='szczegoly_pracownik'),
Maybe somebody know where is the bug?
EDIT:
forms.py
class CudzoziemiecForm(forms.ModelForm):
class Meta:
model = Cudzoziemiec
fields = ('nazwa','imie', 'nazwisko','obywatelstwo', 'data_ur','miejsce_ur','paszport','biometria', 'data_start_pasz', 'data_koniec_pasz', 'dok_pobytowy','cel_wizy', 'data_start_pobyt', 'data_koniec_pobyt')
def __init__(self, user, *args, **kwargs):
super(CudzoziemiecForm, self).__init__(*args, **kwargs)
self.fields['nazwa'].queryset = user.firma_set.all()
self.user = user
def save(self, commit=True):
instance = super(CudzoziemiecForm, self).save(commit=False)
instance.user = self.user
if commit:
instance.save()
return instance
I don't arrive to see the real problem but a couple of things that I would try.
You are using the same almost the same url for different pages. It should not be a problem, but I see that as a possible pitfall. Why don't use something like r'^pracownik/edytuj/$' for the editing form? (sorry for my attempt to make a Polish url :-) ).
Maybe that can avoid possible problems and help to clarify the error.
Also when you say that:
the url redirecting me
Do you mean you are redirected to the form again or to the detail page?

form.is_valid() is returning False when using ModelForm

I am creating a form using ModelForm to let the users upload a file along with a description . The is_valid() function isn't returning true and I am really confused. I have searched and there are many questions with same title as mine but they don't solve my problem.
here is forms.py:
class PostForm(forms.ModelForm):
document = forms.FileField(widget=forms.FileInput)
class Meta:
model = FeedModel
fields = ['description', 'document']
Here is models.py:
class FeedModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField()
like = models.IntegerField(default=0)
dateTime = models.DateTimeField(auto_now=True, auto_created=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def get_absolute_url(self):
u=self.user
return reverse('home:feed',u.primary_key)
Here is views.py:
class PostView(CreateView):
form_class = PostForm
template_name = 'home/feedModel_form.html'
def get(self, request, *args, **kwargs):
form=self.form_class(None)
return render(request, self.template_name, {'form':form })
def post(self, request, *args, **kwargs):
logger = logging.getLogger(__name__)
form=self.form_class(request.POST)
if form.is_valid():
user=request.user
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
logger.error("voila")
redirect({'home:feed'}, user.id)
return render(request, self.template_name, {'form':form })
def feedview(request, user_id):
user = User.objects.get(pk=user_id)
return render(request, 'home/feed.html', {'user': user})
Here is feedModel_form.html:
{% extends 'home/navbar.html' %}
{% block body %}
<div class="form">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'home/form.html' %}
<button type="submit" class="button button-block" `
name="reg_btn">Post</button>`
</form>
</div>
{% endblock %}
Here is form.html:
{% for field in form %}
<div class="field-wrap">
<label>
{{ field.label_tag }}<span class="req">*</span>
</label>
<div>{{ field }}</div>
</div>
{% endfor %}
To see why the form isn't valid, you should check form.errors.
One error will be because you have not passed request.FILES to the form.
form=self.form_class(request.POST, request.FILES)
There may be other errors as well. If you used {{ form }} in your template, Django would include the errors automatically. Since you are rendering the fields manually, it's up to you to include the errors.
The key problem here is that you have overridden post. That means that you're missing out on lots of the code from CreateView.
In your case, it looks like you could remove the post method, and simply override form_valid instead.
def form_valid(self, form):
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
# Note that you had {'home:feed'} here which was incorrect
return redirect('home:feed', user_id)
Your document field expects an uploaded file and is required. In order for the form to actually get the file, you have to also pass it the uploaded file in views.py:
form = self.form_class(data=request.POST, files=request.FILES)

How correctly save multiple files in django?

I need form where user can create article with several images. I use django-multiupload app for image field. I can select several images but when I try to submit the form I have message under the image field: "Field is empty and field is required". Where is my mistake? Why I have such message when image field is not empty?
Also maybe someone can advice good examples or apps to save several images. I would be very grateful for any help.
models.py:
class Article(models.Model):
description = models.TextField(_('Description'))
class Image(models.Model):
article= models.ForeignKey(Article, on_delete=models.CASCADE)
image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')
forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('description', )
image = MultiFileField()
def save(self, commit=True):
instance = super(ArticleForm, self).save(commit)
for each in self.cleaned_data['image']:
Image.objects.create(image=each, article=instance)
return instance
views.py:
def article_add(request):
data = dict()
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
data['form_is_valid'] = True
articles = Article.objects.all
context = {'articles': articles}
context.update(csrf(request))
data['html_article'] = render_to_string('project/article_list.html', context)
else:
data['form_is_valid'] = False
else:
article_form = ArticleForm()
context = {'article_form': article_form}
data['html_article_form'] = render_to_string('project/article_add.html', context, request=request)
return JsonResponse(data)
article_add.html:
{% load widget_tweaks %}
<form method="post" action="{% url 'article_add' %}" class="article-add-form">
{% csrf_token %}
{% for field in article_form %}
<div class="form-group{% if field.errors %} has-danger{% endif %}">
<label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
Try adding "min_num" constraint on the image field,
image = MultiMediaField(min_num=1, media_type='image')
EDIT
def article_add(request):
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
#assume you have already a view in the name 'article_list'.
return redirect('article_list')
else:
article_form = ArticleForm()
context = dict(article_form=article_form)
return render(request, 'project/article_add.html', context)
The problem maybe because you were trying to render two templates in a single view, also when using django template rendering render is a shortcut function, which is mostly preferred to use, rather than string converting and parsing into json.
Also, 'article_list' must be another view, which shows the list of all the articles, after adding a new article, you should consider redirecting to the list view. Here you were trying to render multiple templates, in a single view. You could make of something like this in your list view,
def article_list(request):
articles = Article.objects.all()
context = dict(articles=articles)
return render(request, 'project/article_list.html', context)
Although, these are my personal opinion regarding the code you just shared. Try this approach...

Categories

Resources