save method in a view - python

I have a very simple model:
class Artist(models.Model):
name = models.CharField(max_length=64, unique=False)
band = models.CharField(max_length=64, unique=False)
instrument = models.CharField(max_length=64, unique=False)
def __unicode__ (self):
return self.name
that I'm using as a model form:
from django.forms import ModelForm
from artistmod.artistcat.models import *
class ArtistForm(ModelForm):
class Meta:
model = Artist
but I can't seem to construct a view that will save the form data to the database. Currently I'm using:
def create_page(request):
if request.method == 'POST':
form = ArtistForm(request.POST)
if form.is_valid():
form.save()
return render_to_response('display.html')
else:
form = ArtistForm()
return render_to_response('create.html', {
'form': form,
})
can anyone help the newbie?

Apparently the problem resided in my template. I was using
<form action="display/" method="POST">
as opposed to
<form action="." method="POST">
also changed my HttpRequest object from render_to_response to HttpResponseRedirect
true newbie errors but at least it works now

Related

Django - how add User specific Items?

Good day Stackoverflow,
a user should be able to add multiple titles instead of always overwriting the one added title.
\\ views.py
def edit_profile(request):
try:
profile = request.user.userprofile
except UserProfile.DoesNotExist:
profile = UserProfile(user=request.user)
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return redirect('/test')
else:
form = UserProfileForm(instance=profile)
return render(request, 'forms.html', {'form': form, 'profile': profile})
\\models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
title = models.CharField(max_length=1024)
def __str__(self):
return str(self.title)
\\forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('title',)
Then the user has a form on the website where he can add the specific title.
Until now, however, every time the user fills out the title form, the value in the database is overwritten.
As it should be:
When a new title is added in the form, it should simply be added to it.
At the end I should have the possibility, with a Foor loop in the HTML template, to display all the added titles of the respective user.
Do you know how to do this?
If you are using a relational database, this functionality isn't really supported for a single field. Though, if you really wanted to, you could use a JSON field to make this work.
However, it is probably a better idea to use a separate table for titles.
To do this, you need to create a new Title object like:
class Title(models.Model):
Then, create a many-to-one relationship using ForeignKey:
class Title(models.Model):
text = models.CharField(max_length=1024)
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
The on_delete method is required. This particular one will delete all Titles associated with a UserProfile if a UserProfile is deleted.
Now, if you want to associate a title object with a UserProfile, you would do it like this:
profile = UserProfile(user=request.user)
title = Title.objects.create(text='My Very First Title', user_profile=profile)
For more info on many-to-one relationships in Django: https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/
You can create new model and assign new with the ForeignKey field.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return ', '.join([title for title in self.titles.all()])
class UserTitle(models.Model):
title = models.CharField(max_length=1024)
userprofile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='titles')
def __str__(self):
return self.title
views.py:
def edit_profile(request):
...
if request.method == 'POST':
...
if form.is_valid():
form.instance.userprofile = request.user.userprofile
form.save()
return redirect('/test')
...
admin.py:
from django.contrib import admin
from your_app.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ['id', 'user', '__str__']
admin.site.register(UserProfile, UserProfileAdmin)
settings.py:
INSTALLED_APPS = [
...
'your_app',
...
In template, to make for loop just use:
{% for title in user.userprofile.titles.all %}
{{ title }}
{% endfor %}
or if you need only User titles in single string:
{{ user.userprofile }}

Django auto-generated unique field failing validation on form edit

I am attempting to reuse my create form (EntryForm) for editing a model in Django. My Entry model has a unique slug that is generated on save. This works fine when creating an Entry, but shows the following error when I attempt to edit it:
Entry with this Slug already exists.
I saw several similar questions, but most were failing to set instance= when instantiating the form. I'm pretty sure I'm doing that part correctly.
I've removed other model fields from the code below for clarity.
Here is my model:
class Entry(models.Model):
title = models.CharField(max_length=128, blank=True)
slug = models.SlugField(unique=True, blank=True)
def save(self, *args, **kwargs):
if not self.title:
self.title = self.date.strftime('%B %-d, %Y')
self.slug = slugify(self.title)
super(Entry, self).save(*args, **kwargs)
My view:
def edit_entry(request, entry_slug):
entry = get_object_or_404(Entry, slug=entry_slug)
form = EntryForm(instance=entry, label_suffix='')
if request.method == 'POST':
form = EntryForm(request.POST, instance=entry, label_suffix='')
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print(form.errors)
return render(request, 'journal/entry/form.html', {'form': form})
My form:
class EntryForm(forms.ModelForm):
title = forms.CharField(required=False, max_length=128, label="Title (defaults to date)")
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
class Meta:
model = Entry
exclude = ()
Any ideas?
I did finally figure this out.
The issue was stemming from the fact that I was reusing my create template for the edit form, but forgot to set the form action dynamically depending on which action I desired. So, my 'edit' form was rendering correctly, but actually submitting via the 'create' action.
Thanks to those who commented and to what ultimately led me to debugging the problem, this handy code snippet equivalent to Ruby's binding.pry:
import code; code.interact(local=dict(globals(), **locals()))
I did also take #xyres's advice and remove the slug from my form, as it was unnecessary.
New form:
class EntryForm(forms.ModelForm):
title = forms.CharField(required=False, max_length=128, label="Title (defaults to date)")
class Meta:
model = Entry
exclude = ['slug']
New final line of edit_entry():
return render(request, 'journal/entry/form.html', {'form': form, 'entry': entry})
Form action:
{% if entry %}
<form id="entry_form" method="post" action="/journal/entry/{{ entry.slug }}/edit">
{% else %}
<form id="entry_form" method="post" action="/journal/new_entry/">
{% endif %}

Django: How to make a form with foreignkey

Hi I am working with Django and I am trying to make a little system to register people and teams.
So far I can create teams and people in the admin site.
Now, I want to make a public form, where i.e. a trainer can register his team.
The Team has a foreignkey to Bundesland (the state).
I want a dropdown list that shows the states, I already made in the admin site. And then chose from it in the form. My "python crash course"-book doesn't cover this, so please help me. The answers I found so far in the documentation and on stackoverflow didn't work for me.
models.py:
from django.db import models
class Bundesland(models.Model):
bdl_kurz = models.CharField(max_length=2) #abbreviation
bdl_lang = models.CharField(max_length=25) #full name
--snip--
class Team(models.Model):
bdl = models.ForeignKey(Bundesland)
name = models.CharField(max_length=40)
plz = models.CharField(max_length=5)
ort = models.CharField(max_length=40)
strasse = models.CharField(max_length=40)
strnr = models.CharField(max_length=5)
telefon = models.CharField(max_length=20)
email = models.EmailField()
--snip--
forms.py:
from django import forms
from .models import Team
class TeamForm(forms.ModelForm):
class Meta:
model = Team
bdl = forms.ModelChoiceField(queryset='bdl_lang.objects.all()), empty_label=None)
fields = ['name', 'plz', 'ort', 'strasse', 'strnr', 'telefon', 'email']
labels = {'plz': 'PLZ', 'ort': 'Ort', 'strasse': 'Straße', 'strnr': 'Hausnr.', 'telefon': 'Telefon', 'email': 'Email'}
new_team.html:
<p>New Team</p>
<form action="{% url 'teilnehmer:new_team' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Submit data</button>
</form>
views.py: (if important)
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Bundesland, Gewichtsklasse, Team, Kaempfer
from .forms import TeamForm
--snip--
def new_team(request):
"""Add a new team."""
if request.method != 'POST':
# No data submitted; create a blank form
form = TeamForm()
else:
# POST data submitted; process data.
form = TeamForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('teilnehmer:index'))
context = {'form': form}
return render(request, 'teilnehmer/new_team.html', context)
So I can pick out a number of problems in your code.
bdl = forms.ModelChoiceField(queryset='bdl_lang.objects.all()), empty_label=None) - you do not need the starting quote right after the equal sign.
bdl_lang is a CharField so bdl_lang.objects.all() doesn't make sense. The queryset is an order dict of Django objects (defined via a model class). Replace this with bdl.objects.all(). From here, insert a __unicode__(self) method in your class Bundesland. This method should return the name you want in your choices. From looking at your code, it seems like you would want to return bdl_lang.
You need to include bdl in your fields option.
I hope this helps!

Image is not uploading via form

I am making django project and have one problem with uploading images in forms.
So, I tried to add one object with image, in admin this is working, but in form on site - not.
My views:
def newbook(request, user_id):
form = BookAdd(request.POST or None)
if form.is_valid():
book = form.save(commit=False)
book.author = get_object_or_404(User, pk=user_id)
book.save()
return redirect('../%s' % book.id)
return render(request, 'userbook/newbook.html', {'form': form})
My model:
class Book(models.Model):
"""Book is a compilation of sections with subjects."""
author = models.ForeignKey(AUTH_USER_MODEL)
name = models.CharField(max_length=100)
description = models.CharField(blank=True, max_length=256)
cover = models.ImageField(upload_to='img/bookcovers')
def __str__(self):
return self.name
My form:
class BookAdd(ModelForm):
class Meta:
model = Book
fields = ('name', 'description', 'cover')
When I add new book, I get an error "the field is required", maybe for field of cover, but image added. This work honestly on local server, but don't work on pythonanywhere.com
You have to change code
form = BookAdd(request.POST or None)
to
form = BookAdd(request.POST,request.FILES)
and your form should have enctype="multipart/form-data"
<form action="." method="post" enctype="multipart/form-data">

Extra form fields added in Django form render

I've got a django form setup as follows:
forms.py
class TestimonialForm(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
designation = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}))
testimonial = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control test-form-area'}))
class Meta:
model = Testimonials
models.py
class Testimonials(models.Model):
name = models.CharField(max_length=128)
test = models.CharField(max_length=2000)
credentials = models.CharField(max_length=128)
def __unicode__(self):
return self.name
views.py
def add_testimonial(request):
context = RequestContext(request)
if request.method == 'POST':
form = TestimonialForm(request.POST)
if form.is_valid():
form.save(commit=True)
return index(request)
else:
print form.errors
else:
form = TestimonialForm()
return render_to_response('/add_testimonial.html', {'form': form}, context)
On render, I see the three main fields that I defined in forms.py that have the classes form-control added to them. However, I also see two extra fields that have no styling attached to them. Any idea what's going wrong?
Your form defines the fields name, designation and testimonial, but the model provides name, test and credentials. So the name field gets redefined with the extra styling, but the other two fields are simply added to the default fields provided by the model. If you want to override them, you need to use the same names.

Categories