All I'm trying to do is save the simple form. Everything looks fine but after I click save and the form is re-rendered there is no new trade in the Database. No error message is thrown either.
At first, I thought there was an issue with the user but it looks fine as well. Been reading a lot of documentation on this topic but haven't found where the issue is yet.
Thanks for any help and please let me know if there is anything extra I can add.
create.html
<form id='trade_create_view' method='POST' action='.'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='Submit' >
</form>
views.py
def trade_create_view(request):
form = TradeForm(request.POST or None, instance=request.user)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = TradeForm()
context = {
'form': form,
}
return render(request, "tj/cp/trade/create.html", context)
forms.py
from django import forms
from .models import Trade
class TradeForm(forms.ModelForm):
class Meta:
model = Trade
fields = [
'user',
'target_size',
'target_entry',
'target_exit',
'ticker',
'exchange',
'short',
'comments',
'size',
'entry_price',
'exit_price',
'entry_date',
'exit_date',
'fees',
'permission',
]
exclude = ['user',]
model.py
class Trade(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
comments = models.TextField(max_length=10000, blank=True, null=True)
created = models.DateField(auto_now_add=True)
last_edit = models.DateField(auto_now=True)
#general trade info
ticker = models.ForeignKey(Ticker, on_delete=models.CASCADE)
short = models.BooleanField(default=False)
exchange = models.ForeignKey(Exchange, on_delete=models.CASCADE)
#target trade outline
target_size = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
target_entry = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
target_exit = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
#real trade
size = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
entry_price = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
exit_price = models.DecimalField(null=True, blank=True, max_digits=50, decimal_places=20)
entry_date = models.DateField(blank=True, null=True, default=datetime.now)
exit_date = models.DateField(blank=True, null=True, default=datetime.now)
fees = models.DecimalField(blank=True, null=True, max_digits=50, decimal_places=20)
PER_OPTIONS = [
('0', 'Public'),
('1', 'Private'),
('2', 'Mentor Only'),
]
permission = models.CharField(max_length=1, choices=PER_OPTIONS, default=0)
I think you just have to check if your request is a post or a get method:
def trade_create_view(request):
if request.method == "POST":
form = TradeForm(request.POST or None, instance=request.user)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = TradeForm()
context = {
'form': form,
}
return render(request, "tj/cp/trade/create.html", context)
OR
You just can add a post def to your view as follows:
def post(self, request):
form = TradeForm(request.POST or None, instance=request.user)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = TradeForm()
...
This line doesn't make sens: TradeForm(request.POST or None, instance=request.user)
When you use instance for your form, you give an instance of the object concerned. But your object is Trade not User. You can choose different ways to solve the problem, I give one:
def trade_create_view(request, id):
form = TradeForm()
if request.method == "POST":
trade, created = Trade.objects.get_or_create(id=id) # you get or create your instanced Trade
form = TradeForm(request.POST, instance=trade) # you give to your form the instance of your Trade
if form.is_valid():
print(form.cleaned_data)
form.save()
context = {
'form': form,
}
return render(request, "tj/cp/trade/create.html", context)
I arbitrarily took the id to query an object Trade. As I understand your code you can use this function to create and edite any Trade object with your TradeForm.
get_or_create is document on the Django Website. If you don't when to use it, you can use Trade.objects.get(id=id) you you need to check if the object exist before.
But if you just when to create an object Trade just remove instance=XXX, and use TradeForm(request.POST). Instance is used to get an object in your database and overwrite with the new data posted and processed by your form.
So I switched everything over to Class-Based Views and for some reason now it works perfectly and instantly.
What came even more as a shock is that when I checked my database again after the first Class-Based View test there were about 15 test trades that now appeared (and trust me I checked/refreshed the database after every function view test). So.. I guess it worked all along which is nice because I really read the documentation 10x to figure out what was wrong and was getting really frustrated. What's not so nice is that the database took hours to update or maybe they were frozen somewhere else. That I can't explain yet.
the new views.py
class TradeCreateView(CreateView):
template_name = "tj/cp/trade/create.html"
form_class = TradeForm
queryset = Trade.objects.all()
def form_valid(self, form):
print(form.cleaned_data)
return super().form_valid(form)
Thanks for the help everyone!
I know this maybe not the perfect resolve you guys were hoping for but at least there is some closure.
Related
I am making a todo app for practice, the functionality I want to achieve is that, when a user create a task,Only the time field should be unique about all of his tasks, I have done (unique=True) In the time field in model but that make it unique all over the database, but I want it to be unique only with the tasks associated with the user.
the view is below:
#login_required(login_url='login')
def home(request):
tasks = Task.objects.filter(name__username=request.user.username)
form = TaskForm()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.name = request.user
obj.save()
return redirect('home')
else:
print(request.POST)
print(request.user.username)
messages.warning(request, 'Invalid Data!')
return redirect('home')
context = {'tasks' : tasks}
return render(request, 'task/home.html', context)
task model:
class Task(models.Model):
choices = (
('Completed', 'Completed'),
('In Complete', 'In Complete'),
)
name = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
task = models.CharField(max_length=200, null=False, blank=False)
time = models.TimeField(auto_now_add=False, blank=True)
status = models.CharField(max_length=200, choices=choices, null=True, blank=False)
def __str__(self):
return self.task
def get_task_author_profile(self):
return reverse('profile')
as you can see, I want to show the task that the logged in user has added.
the form is:
class TaskForm(ModelForm):
class Meta:
model = Task
fields = '__all__'
exclude = ['name']
the functionality I talked about above, I tried to achieve through view:
#login_required(login_url='login')
def home(request):
tasks = Task.objects.filter(name__username=request.user.username)
time = []
for task in tasks:
time.append(task['time'])
form = TaskForm()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid() and form.cleaned_data['time'] != time:
obj = form.save(commit=False)
obj.name = request.user
obj.save()
return redirect('home')
else:
print(request.POST)
print(request.user.username)
messages.warning(request, 'Invalid Data!')
return redirect('home')
context = {'tasks' : tasks}
return render(request, 'task/home.html', context)
but that gave an error: TypeError: 'Task' object is not subscriptable
I know its not right, but how can I achieve it, does Django have anything that can provide such fuctionality?
The problem is coming from here:
for task in tasks:
time.append(task['time']) #<--
Here if you want to use access time, you need to use task.time because task is an object.
Also need to fix another thing in your exisiting code to make it work, because time is a list:
if form.is_valid() and form.cleaned_data['time'] in time:
# ^^^
BTW, you don't need to make it that complicated, you can add Database level constraint from the model to make the times unique for a specific user. Also, use DateTime field for that. You can use unique_togather for that:
class Task(models.Model):
choices = (
('Completed', 'Completed'),
('In Complete', 'In Complete'),
)
name = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
task = models.CharField(max_length=200, null=False, blank=False)
time = models.DateTimeField(auto_now_add=False, blank=True)
status = models.CharField(max_length=200, choices=choices, null=True, blank=False)
class Meta:
unique_togather = ['name', 'time']
I have two models:
class Checklist(models.Model):
author = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
client_name = models.ForeignKey(Client, on_delete=models.CASCADE,
related_name='details')
fieldA = models.CharField(max_length=25, blank=True, null=True)
fieldA_Check= models.BooleanField(default=False)
fieldB = models.CharField(max_length=25, blank=True, null=True)
fieldB_Check= models.BooleanField(default=False)
class Client(models.Model):
client_fieldA = models.CharField(max_length=25)
client_fieldB = models.CharField(max_length=25)
client_fieldC = models.CharField(max_length=25)
Now I trying to change Client instance fields values via Checklist using following code:
#login_required
def create_order(request, pk):
instance = get_object_or_404(CheckList, id=pk)
form = myForm(request.POST or None, instance=instance)
if form.is_valid():
form.save()
messages.success(request, 'Test message')
return get_PDF_order(request, pk)
return render(request, 'templates/create_order.html', {'form': form})
here is my form:
class myForm(forms.ModelForm):
class Meta:
model = Client
fields = ('client_fieldA', 'client_fieldB', 'client_fieldC')
widgets = {
'client_fieldA': forms.TextInput(attrs={'class': 'form-control'}),
'client_fieldB': forms.TextInput(attrs={'class': 'form-control'}),
'client_fieldC': forms.TextInput(attrs={'class': 'form-control'}),
}
And it works but only once. Data saved and I get a pdf file with this data, but subsequent attempts do not change anything. The field value still the same. I'm guessing that it is because I working with the Checklist instance but not Client. So, my questions are: 1) How I can get an access to all Client fields (a queryset of all Client fileds) via Checklist? 2) Although my code is incorrect - why does it work (once)? I mean why does it save first time?
Thank you all in advance!
To formalize the answer, the instance is actually an instance of the model the form is based on. Thus, in your case, you cannot pass a CheckList instance to a form based on Client
Anyway, as far as you have the CheckList id, you can easily obtain the Client, and the code for your view will be:
#login_required
def create_order(request, pk):
instance = get_object_or_404(CheckList, id=pk)
form = myForm(request.POST or None, instance=instance.client_name)
if form.is_valid():
form.save()
messages.success(request, 'Test message')
return get_PDF_order(request, pk)
return render(request, 'templates/create_order.html', {'form': form})
You pass it always the same instance, so what happens is that you are probably overwriting the same record over and over.
I would recommend you to split this using the django-provided generic class-based views CreateView and UpdateView.
Stop reinventing the wheel, use class-based views. It'll pay off big time in the long term.
I'm used to collecting the current logged in user in a CreateView and passing it to the form like so:
class MakeFantasyTeam(CreateView):
form_class = MakeFantasyTeamForm
[...]
def form_valid(self, form):
form.instance.team_manager = self.request.user
form.save()
return super(MakeFantasyTeam, self).form_valid(form)
However, this doesn't seem to work when using an InlineFormSetView as provided by django-extra-views. I get an error NOT NULL constraint failed: tournament_invite.invited_by_id and I'm not sure how to get the user.id passed on to the form.
My View:
class InvitePlayersView(InlineFormSetView):
template_name = 'invite_players.html'
model = Tournament
inline_model = Invite
form_class = InvitePlayerForm
pk_url_kwarg = 'tourney_id'
factory_kwargs = {'can_delete': False, 'extra': 1}
def formset_valid(self, formset):
tourney_id = self.kwargs['tourney_id']
formset.instance.invited_for = Tournament.objects.filter(id=tourney_id).get()
formset.instance.invited_by = self.request.user
formset.save()
return super(InvitePlayersView, self).formset_valid(formset)
def get_success_url(self):
return reverse('make_team', kwargs={'tourney_id': self.object.invited_for.id})
My Model:
class Invite(models.Model):
name = models.CharField(max_length=200, blank=True, null=True)
email = models.CharField(max_length=320, null=False, blank=False, validators=[EmailValidator],)
invited_by = models.ForeignKey(get_user_model(), on_delete=models.DO_NOTHING)
invited_for = models.ForeignKey(Tournament, on_delete=models.DO_NOTHING)
created_dt = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.email
def get_absolute_url(self):
return reverse('home')
My Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = Invite
fields = ('name', 'email',)
Any tips or hints much appreciated!
Thank you,
Jon
Edit: Just to clarify what I'm trying to do here; I want a user to submit a formset. The data of that formset should be stored in the model, and the userid of the submitting user should also be stored in the model. I don't seem to be able to pass on the userid though.
I am not sure what you exactly want to do here, As per my understanding you want to use the currently logged in user's information. To do so you can append the user's info in the session dictionary. After that you can use the information in templates or in other views too.
In authentication view
def login(request):
#your necessary data
request.session['user_id']=The_user_id
request.session['user_name']=The_userName
To access data in the template
{% request.session.user_id %}
{% request.session.user_name %}
To access data in other views
def myview(request):
user_id= request.session['user_id']
user_name= request.session['user_name']
I am unsure how to tie a logged in user to a submitted form using regular Django forms. I see alot of examples using ModelForms but none (that I can tell) without using the ModelForms. In my forms.py im having a hard time figuring out how to add the author field. I cannot just add author = forms.ForeignKey or something like that. Then somehow in my view i need to call the author field to be saved into the database (my below example is my best guess and probably not right with the "tenant_form.author = request.user").
I have a model that looks like this and has a user Foreignkey setup:
class AppyModel(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
date_time_form_filled = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
I have a forms.py:
class TenantForm(forms.Form):
first_name = forms.CharField(required=False, label='First Name')
last_name = forms.CharField(required=False, label='Last Name')
I have a views.py
#login_required
def tenant_create_form_view(request):
tenant_form = TenantForm()
if request.method == 'POST':
tenant_form.author = request.user
tenant_form = TenantForm(request.POST)
if tenant_form.is_valid():
print(tenant_form.cleaned_data)
AppyModel.objects.create(**tenant_form.cleaned_data)
else:
print(tenant_form.errors)
context = {
'form': tenant_form
}
return render(request, 'fill_appy.html', context)
You should add author when the form is valid,
tenant_form = TenantForm()
if request.method == 'POST':
tenant_form = TenantForm(request.POST)
if tenant_form.is_valid():
obj = tenant_form.save(commit=False)
obj.author = request.user #add author here
obj.save()
# .. rest of code
Im trying to make a simple voting app.
The user should be presented with a blank form at first, but when the user has filled in the form, the user should be presented with the same form, but with the data they filled in.
How can I present the data they put in, on the same form?
My model:
class Vote(models.Model):
user = models.ForeignKey(User)
vote_1 = models.ForeignKey(Song, null=True, blank=True, related_name="voted_1")
vote_2 = models.ForeignKey(Song, null=True, blank=True, related_name="voted_2")
vote_3 = models.ForeignKey(Song, null=True, blank=True, related_name="voted_3")
creation_date = models.DateTimeField(auto_now_add=True)
edited = models.DateTimeField(auto_now=True)
My view:
def show_voteform(request):
if request.method == 'POST':
form = VoteForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Vote saved", extra_tags='alert-success')
#Return the user to same page
return HttpResponseRedirect('/vote/')
else:
form = VoteForm(initial={'user':request.user, 'vote_1':???, 'vote_2':???, 'vote_3':???,})
return render(request, 'vote/form.html', {
'form': form,
})
Is this something I could provide in initial, or do I have to do this another way?
Edit:
Changed it to this:
else:
try:
vote = Vote.objects.filter(user=request.user).latest('creation_date')
form = VoteForm(instance=vote)
except Vote.DoesNotExist:
form = VoteForm(initial={'user':request.user})
If your VoteForm is a ModelForm, then you can show the form with data from a model instance filled in using:
# get the most recent Vote by this user
vote = Vote.objects.filter(user=request.user).latest('creation_date')
# fill in the form with data from the instance
form = VoteForm(instance=vote)