So I'm new to django and I'm struggling with the documentation for class based views. Not really sure what I'm doing wrong here, but this is the problem:
I fill in the appropriate data on the form, click submit and I'm redirected to the same url plus some get parameters that correspond to what I submitted in the form. Nothing new is added to the db. I would like to create a new Advertisement row in the db when I click submit.
I have a ModelForm as follows:
class NewAdForm(ModelForm):
class Meta:
model = Advertisement
exclude = ('campaign',)
def __init__(self, campaign, *args, **kwargs):
super(NewAdForm, self).__init__(*args, **kwargs)
self.campaign = campaign
I also have a FormView:
class AddAdvertView(FormView):
form_class = NewAdForm
template_name = 'advertisers/newad.html'
def get_form_kwargs(self):this
kwargs = super(AddAdvertView, self).get_form_kwargs()
kwargs['campaign'] = get_object_or_404(Campaign, id__exact = self.kwargs['campaign_id'])
return kwargs
def form_valid(self, form):
form.save(commit = True)
return super(AddAdvertView, self).form_valid(form)
And here's the template:
<form action="" method="get">
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
Any reason why you're using method="get"? The FormView class is probably expecting a POST in order to trigger validation and saving. GET is usually just used to render the initial form.
It's possible that it's because you're missing the CSRF token, but it really should give you an error about that. Still, try:
<form action="" method="get">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
Also, while it doesn't explain why the form isn't saved, you need to specify a success_url on your FormView, the URL the user should be redirected to after successfully submitting the form. I've actually never tried leaving it off, but it's possible that the view is taking you back to the form simply because it doesn't know where else to go.
Related
I have a DetailView Based on a model ( A ) and on the same template I have a ModelFormView from a model B which has FK to model (A)
The data from form doesn't get saved to the database.
This is the DetailView:
class LocationView(DetailView):
template_name = "base/stocks/location.html"
model = LocationStock
def get_context_data(self, **kwargs):
context = super(LocationView, self).get_context_data(**kwargs)
context['form'] = OutsModelForm
return context
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(LocationStock, id=id_)
This is the FormView:
class OutsAdd(FormView):
form_class = OutsModelForm
success_url = reverse_lazy('base:dashboard')
def form_valid(self, form):
return super().form_valid(form)
This is the url.py:
path('locations/<int:id>', LocationView.as_view(), name='location-detail'),
path('locations/outs', require_POST(OutsAdd.as_view()), name='outs-add'),
This is the template:
<form method="POST" action="{% url 'outs-add' %}" >
<div class="modal-content">
{% csrf_token %}
{% render_field form.quantity placeholder="Quantity"%}
{% render_field form.id_year placeholder="Year"%}
{% render_field form.id_location placeholder="ID Location"%}
</div>
<div class="modal-footer">
<input class="modal-close waves-effect waves-green btn-flat" type="submit" value="Save">
</div>
</form>
The data gets POSTED in the /locations/outs but is not saving to the actual database.How can I save it ?
The functionality of Django's FormView is really only meant to display a form on a GET request, show form errors in the case of form_invalid, and redirect to a new URL if the form is valid. In order to persist the data to the database you have two options. First you can simply call form.save() in your FormView:
class OutsAdd(FormView):
form_class = OutsModelForm
success_url = reverse_lazy('base:dashboard')
def form_valid(self, form):
form.save()
return super().form_valid(form)
Or, you can use the generic CreateView. Django's CreateView is similar to a FormView except it assumes it's working with a ModelForm and calls form.save() for you behind the scenes.
Who can help me with the following challenge?
I have a registration template where users can sign up. They are then redirected to an url with a payment button and activated when a successful payment is made. In the HTML template I store the username in a custom field within the payment button which is used to later activate the account. Now since the user is not activated/logged in yet, I can't call the user object yet like {{user.username}}. So I want to try sessions to solve this and capture the username during registration to retrieve this session variable and put it in my custom field on a different page. But how? I tried using request.session but I’m not sure where to fit this the files below and then how to call this variable in the html template.
Any advise or help is greatly appreciated!
Here is my regbackend.py
class MyRegistrationView(RegistrationView):
form_class = UserProfileRegistrationForm
def register(self, form_class):
user_package.username = form_class.cleaned_data['username']
And here my forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = SignUp
fields = ['username', 'email']
Here my registration.html
<form method="post" action=".">
{% csrf_token %}
{{ form.username|as_crispy_field }}
<input class="btn btn-success" type="submit" value="{% trans 'Submit' %}" /></form>
And finally my HTML Template for after registration with the payment button and custom field.
<form action="some-url" method="post" target="_top">
<input type="hidden" name="custom" value="{{ session.username? }}">
</form>
Im using Django 1.9x and Django-registration-redux
This is how I keep the session to use it on another view.
On your registration form :
def registration(request):
initial={'username': request.session.get('username', None)}
form = RegistrationForm(request.POST or None, initial=initial)
if request.method == 'POST':
if form.is_valid():
request.session['username'] = form.cleaned_data['username']
return HttpResponseRedirect(reverse('your_checkout_view'))
return render(request, 'registration.html', {'form': form})
Once the username field is completed and the form submited it goes to the second view in which you can take the username that is stored in your session.
Just like this :
def your_checkout_view(request):
username = request.session['username']
...
From there you can take the stored username and do what you have to do.
I would like to do the following:
With my model
class User(models.Model):
id = models.AutoField(primary_key=True)
field1 = models.CharField(max_length=100)
fk1 = models.ForeignKey(Group)
goes on
After this, I created my Serializer, which looks like:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = UserSerializer
fields = (...)
...
Lastly, I create my ViewSet, which should look like this:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
but now, how would I be able to create a viewSet and, for example, generate a form with my class? My final idea is to be able to do something like:
def my_view(request):
my_form = UserViewSet.as_view({'get': 'list'}(request))
# from here either to be able to use .render().content
# or, inside the template, render with {% render_form my_form %}
Is this possible? Thank you
What you're suggesting is possible, but it doesn't usually make sense. Django Rest Framework is great for creating an API so that you can send and receive information to and from that api, maybe in JSON format.
Getting a form involves getting rendered HTML from the server. That's a better task for Django itself. You could use a CreateView to do what you're trying to:
def UserCreateView(CreateView):
model = User
form_class = "name_of_your_form.html" # Or you could call the form 'user_create_form.html` and leave this line out.
fields = [...]
Your form will then be available in your template, per the docs:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
As docs says:
Serializers may be rendered as forms by using the render_form template tag, and including the serializer instance as context to the template.
Next example will probably work for you. But how #YPCrumble sayed DRF goal is easy and fast build an API, not rendering forms
class UserDetail(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'your_template.html'
def get(self, request, pk):
serializer = UserSerializer(profile)
return Response({'serializer': serializer})
def post(self, request, pk):
user = get_object_or_404(User, pk=pk)
serializer = UserSerializer(data=request.data)
if not serializer.is_valid():
return Response({'serializer': serializer})
serializer.save()
return redirect('some_url_name')
template file:
{% load rest_framework %}
<html><body>
<form action="{% url 'user_url' pk=user.pk %}" method="POST">
{% csrf_token %}
{% render_form serializer %}
<input type="submit" value="Save">
</form>
</body></html>
`DRF Docs link
I have a template which displays a certain ModelForm at one of the URLs of my Django site. The ModelForm is based on a model with two fields,
class ActionCode(models.Model):
action_code = models.CharField(blank=False, max_length=10,
verbose_name="Action Code")
description = models.TextField(blank=True)
class Meta:
unique_together = ('action_code',)
I would like my ModelForm to give the user only the first field (Action Code), then when it is submitted, verify if the value entered already exists or not. If it doesn't already exist, I want to redirect the user to be able to enter a Description for that Action Code (the second field in my model). So I wrote a second ModelForm which uses the Description field of the model, and I would like my first form to redirect to the second form after validating that the data is new. Ideally then, the Description would be linked to this specific piece of data and both would go into the same Django database table (hence them coming from the same model). However, when I enter a new piece of data and hit Submit, the site simply stays at the /action_code/ URL and displays a Submit button, and nothing else. How do I get the first form to redirect to the second form, and what is the best way to make sure it only does so if the data is new?
Here are my urls.py:
url(r'^action_code/', action_code_form, name="actioncode"),
url(r'descr_form/', code_description_form, name='description'),
Here are my two forms in `forms.py':
class ActionCodeForm(ModelForm):
class Meta:
model = ActionCode
fields = ('action_code',)
class ActionCodeDescriptionForm(ModelForm):
class Meta:
model = ActionCode
fields = ('description',)
Here is my views.py:
def action_code_form(request):
form = ActionCodeForm()
description_form = ActionCodeDescriptionForm
if request.method == 'POST':
form = ActionCodeForm(request.POST)
if form.is_valid():
action_code = form.cleaned_data['action_code']
form.save()
return render(request, 'description_form.html',
{'form': description_form})
return render(request, 'action_code_form.html', {'form': form})
def code_description_form(request):
form = ActionCodeDescriptionForm()
if request.method == 'POST':
form = ActionCodeDescriptionForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'description_form.html', {'descr_form': form})
And my templates:
action_code_form.html:
<form method="post" action="">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="Submit"/>
</form>
description_form.html:
<form method="post" action="">
{% csrf_token %}
<table>
{{ descr_form }}
</table>
<input type="submit" value="Submit"/>
</form>
Forms don't redirect to anything. It's the view's responsibility to do the redirect.
You need two views, with two URLs; when the first form submission is successful, the view should redirect to the second URL.
I'm trying to get uploading working with Django. I don't get an error when I try to upload it, and the new Item is saved, but there is no image. The other form data is all there. I've been googling and on stack overflow for the past 2 days and cannot find a fix. I don't even know where it's going wrong! Any advice would be amazing. Thanks so much. :)
from views.py:
if request.method == 'POST':
form = ItemForm(request.POST, request.FILES, user=request.user, forsale=True)
if form.is_valid():
new_item = form.save()
return item_view(request, marketplace_id, new_item.id)
else:
form = ItemForm(user=request.user)
from models.py:
class Item(models.Model):
photo = StdImageField(upload_to='images/', blank=True, size=(500, 500, True), thumbnail_size=(210, 150, True))
user = models.ForeignKey(User)
...
def __unicode__(self):
return self.name
class ItemForm(ModelForm):
class Meta:
model = Item
fields = ['name', 'description', 'price', 'shipping', 'photo', 'section']
def __init__(self, *args, **kwargs):
self._user = kwargs.pop('user')
super(ItemForm, self).__init__(*args, **kwargs)
from the template:
<form enctype="multipart/form-data" action="" method="post" data-ajax="false">{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper" data-role="fieldcontain">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<input type="submit" value="Save">
</form>
As I see it, the template is correct. The Item model seems fine, StdImageField is a wrapper for ImageField. It works fine in the admin panel.
The Form seems fine as well, nothing special.
In my views.py fine, I check for a POST request, call the ItemForm and pass in request.POST and request.FILES (and forsale which is a boolean). I check if the form is valid, if so, I save it. Why isn't it working? The Item saves but in the admin panel there is no file associated with 'photo'.
Check that MEDIA_ROOT setting joined with "images/" is a valid and writable path for Django process.
Also using pdb
import pdb; pdb.set_trace()
can help you in the process of finding the issue, (f.i. have a look at request.FILES to see if everything looks ok there during post).