ModelForm in Django not saving anything - django

I am making a twitter clone app in Django. I have a model, and a modelform as so:
Class Tweet(models.Model):
content = models.TextField(blank=True, null=True)
image = models.FileField(upload_to='images/', blank=True, null=True)
class TweetForm(forms.ModelForm):
class Meta:
model = Tweet
fields = ['content',]
def clean_content(self):
content = self.cleaned_data.get('content')
if len(content) > MAX_TWEET_LENGTH:
raise forms.ValidationError('This tweet is too long')
I have a view for this:
def tweet_create_view(request, *args, **kwargs):
if request.method == 'POST':
form = TweetForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
form = TweetForm()
context = {
'form': form
}
return render(request, 'components/form.html', context)
and the template:
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-secondary" type="submit">Save</button>
</form>
When I submit the form data, in the database the value is shown as NULL, even if I pass in some text. What am I doing wrong??

You are not returning the cleaned form data from the clean function, as your clean function doesn't return anything if it passes the validation, it saves None/Null to DB.
def clean_content(self):
content = self.cleaned_data.get('content')
if len(content) > MAX_TWEET_LENGTH:
raise forms.ValidationError('This tweet is too long')
return content

Related

how to delete previous uploaded file when a new one gets uploaded using id

I have simple cv upload class for users to upload their resume. it works just fine but when they upload a newer one, the previous wont get deleted.
this is my code:
class ResumeDocument(models.Model):
id = models.AutoField(primary_key=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
cvfile = models.FileField(upload_to="documents", null=True, validators= [validate_file_extension])
#property
def filename(self):
return os.path.basename(self.cvfile.name)
how can I reach the previous id? id = self.id - 1. something like that.
this is my views:
#login_required
def pdf_resume(request):
if request.method == 'POST':
form = DocumentForm(request.POST,request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('pdf_resume')
if 'delete' in request.GET:
return delete_item(ResumeDocument, request.GET['id'])
else:
form = DocumentForm()
documents = ResumeDocument.objects.filter(user=request.user)
if documents:
form = DocumentForm(instance=documents[0])
context = {
'form':form,
'documents':documents,
}
return render(request, 'reg/pdf_resume.html', context)
and this is also my HTML code:
<form id="document-form" method="POST" enctype="multipart/form-data" action="{% url 'pdf_resume' %}" autocomplete="off" class="ant-form ant-form-horizontal">
{% csrf_token %}
<p>{{ form }}</p>
<div class="ant-row-flex" style="margin-left: -10px; margin-right: -10px;"></div>
<button id="btn_submit" type="submit"
class="ant-btn ant-btn-primary"
ant-click-animating-without-extra-node="false" style="float: left;"><span>upload</span></button>
</form>
One possible solution is to save all uploaded CVs for each user and track the last uploaded CV with field uploaded_on. You may refer to the below high-level example:
class CVFile(models.Model):
file_name = models.CharField(max_length=200)
cv_file = models.FileField(upload_to="documents", null=True, validators=[validate_file_extension])
uploaded_on = models.DateTimeField(default=timezone.now, blank=True)
class ResumeDocument(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
cv_file = models.ForeignKey(CVFile, on_delete=models.CASCADE)
You will need to amend your HMTL and views.py accordingly.
models.py
class ResumeDocument(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
cvfile = models.FileField(upload_to="documents", null=True, validators=
[validate_file_extension])
views.py(i just look is there any resumedocuments for that user if yes so i give him
the form just if he was editing the existing file)
#login_required
def pdf_resume(request):
if request.method == 'POST':
form = DocumentForm(request.POST,request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('pdf_resume')
if 'delete' in request.GET:
return delete_item(ResumeDocument, request.GET['id'])
else:
form = DocumentForm()
documents = ResumeDocument.objects.filter(user=request.user)
if documents:#new
form = DocumentForm(instance=documents[0])
context = {
'form':form,
'documents':documents,
}
return render(request, 'reg/pdf_resume.html', context)
now inside your pdf_resume.html your can just pass the 'form' because you already check if that user has a document or not.

how can users upload file into Django model?

With these codes, I want each user to be able to upload their own file in their own model
forms.py:
class sp_UserNewOrderForm(forms.Form):
file= forms.FileField()
models.py:
class sp_Order(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.owner.username
class sp_OrderDetail(models.Model):
order = models.ForeignKey(sp_Order, on_delete=models.CASCADE)
file= models.FileField()
def __str__(self):
return self.order.owner.username
views.py:
#login_required
def add_user_order(request):
new_order_form = sp_UserNewOrderForm(request.POST or None)
if new_order_form.is_valid():
order = sp_Order.objects.filter(owner_id=request.user.id).first()
if order is None:
order = sp_Order.objects.create(owner_id=request.user.id)
file= new_order_form.cleaned_data.get('file')
order.sp_orderdetail_set.create(file=file)
# todo: redirect user to user panel
# return redirect('/user/orders')
return redirect('/')
return redirect('/')
HTML:
<form method="post" action="/add_sp">
{% csrf_token %}
{{ form.count }}
<button type="submit" class="btn btn-primary container">
upload
</button>
</form>
But these codes do not create the model. what is the problem?
The problem appears to be in this line:
order = sp_Order.objects.filter(owner_id=request.user.id).first()
I think you should replace owner_id = request.user.id with owner = request.user
owner_id is not an attribute of the model you're trying to filter or create
You need to include request.FILES when instantiating the form for the POST request.
def add_user_order(request):
if request.method == 'POST':
new_order_form = sp_UserNewOrderForm(request.POST, request.FILES)
if new_order_form.is_valid():
order = sp_Order.objects.filter(owner_id=request.user.id).first()
if order is None:
order = sp_Order.objects.create(owner_id=request.user.id)
file= new_order_form.cleaned_data.get('file')
order.sp_orderdetail_set.create(file=file)
# todo: redirect user to user panel
# return redirect('/user/orders')
return redirect('/')

Django TypeError, invite users to 'team'

I want to signed in user to be able to invite users to a 'team', where the teams they can select from are only those they are a part of. I keep getting the same error (init() missing 1 required positional argument: 'user') when I try and output a list of all teams in model UserTeams where the userID = current logged in user.
My view:
def invite(request):
if request.method == 'POST':
form = InvitePlayerForm(request.POST)
if form.is_valid():
userteam = form.save(commit=False)
userteam.save()
else:
form = InvitePlayerForm()
query = UserTeams.objects.all()
return render(request, 'teammanager/invite.html', {
"invite": query,
"form": form
})
My Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = UserTeams
fields = ['userID','teamID']
def __init__(self,user,*args,**kwargs):
super (InvitePlayerForm,self ).__init__(user,*args,**kwargs)
self.fields['teamID'].queryset = Team.objects.filter(id__in =
UserTeams.objects.filter(userID = user))
My UserTeams model:
class UserTeams(models.Model):
userID = models.ForeignKey(User,on_delete=models.CASCADE)
teamID = models.ForeignKey(Team,on_delete=models.CASCADE)
My HTML:
<html>
<body>
<h4>Invite players to your team</h4>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input class="btn btn-success" type="submit" value="Add Player"></button>
</form>
You've redefined the signature of the form so that it accepts a user element. But you haven't actually passed that user when you create the form. How else are you expecting it to get into the form?
if request.method == 'POST':
form = InvitePlayerForm(request.user, request.POST)
...
else:
form = InvitePlayerForm(request.user)
(Note also, your queryset would be better as Team.objects.filter(userteam__UserId=user.)

Forms from models

I have different models:
Cars
Pictures (models.ForeignKey(Cars))
CarsOptions(models.OneToOneField(Cars))
Then I want, that user can add new cars. Forms.py:
class NewCarsForm(ModelForm):
class Meta:
model = Cars
exclude = ('checked','user')
In views.py:
#login_required
def add_car(request):
form = NewCarsForm(request.POST or None)
if form.is_valid():
cmodel = form.save()
cmodel.save()
return redirect(profile)
return render(request, 'add_car.html', { 'form': form,})
I have a few questions (yes, I read this).
As you can see, user can add only "car", not pictures and options. How to do this on one page in one form?
exclude = ('checked','user'), it means, that I want to make all new positions with checked=0, so I can filter them. And the user-field - users cant choose user in a list. How to take user id (who adds car) in form.save()?
Thanks.
Update:
class Pictures(models.Model):
cars = models.ForeignKey(Cars, related_name='pictures')
width = models.PositiveIntegerField(editable=False, default=640)
height = models.PositiveIntegerField(editable=False, default=480)
image = models.ImageField(upload_to=lambda inst, fname: 'users_img/' + 'cars' + fname, height_field='height', width_field='width', max_length=100)
def __unicode__(self):
return str(self.id)
forms.py
class NewCarsForm(ModelForm):
class Meta:
model = Cars
exclude = ('checked','user')
PicturesFormset = inlineformset_factory(Cars, Pictures,
fields=('field_name', 'field_name'), can_delete=True)
CarsOptionsFormset = inlineformset_factory(Cars, CarsOptions,
fields=('field_name', 'field_name'), can_delete=True)
views.py
#login_required
def add_car(request):
cars = Cars(user=request.user)
if request.method == 'POST':
form = NewCarsForm(request.POST, instance=cars)
if form.is_valid():
cmodel = form.save()
picture_formset = PicturesFormset(request.POST, request.FILES,
instance=cmodel)
if picture_formset.is_valid():
picture_formset.save()
option_formset = CarsOptionsFormset(request.POST, instance=cmodel)
if option_formset.is_valid():
option_formset.save()
return redirect(profile)
form = NewCarsForm()
picture_formset = PicturesFormset(instance=Cars())
option_formset = CarsOptionsFormset(instance=Cars())
return render(request, 'add_car.html', {
'form': form,
'picture_formset': picture_formset,
'option_formset': option_formset,
})
template
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<h4>Car:</h4>
{{ form.as_p }}
<h4>Picture:</h4>
{{ picture_formset.as_p }}
<h4>Options:</h4>
{{ option_formset.as_p }}
<input type="submit" value="Submit">
</form>

ModelForm. Why my form is not filled with data from model?

Why my form is not filled with data from model?
This is my model.py
class People(models.Model):
user = models.OneToOneField(User)
name = models.CharField(max_length=100)
address = models.CharField(max_length=255)
This is my forms.py
from django.forms import ModelForm
class EditForm(ModelForm):
class Meta:
model = People
exclude=('user',)
views.py
def edit_data(request):
user = request.user
people = People.objects.get(user=user)
form = EditForm(request.POST, instance = people)
if request.method == 'POST':
if form.is_valid():
form.save()
else:
print 'Error'
else:
form = EditForm()
return render_to_response('profile.html',{'form':form}, context_instance=RequestContext(request))
profile.html
<form action="/profile/" method="post">{% csrf_token %}
{{ form.as_p }}
</form>
The problem is that you're redefining form in your else clause (to a new instance of your EditForm, which doesn't have the instance variable set). Remove the else (and the line under it) and you should be good to go.