I have a ModelChoiceField called outage_name. I also have a simple form that allows you to select the item from the list. The ModelChoiceField is pulled from a MySQL DB. This queryset is located in forms.py
outage_name = forms.ModelChoiceField(queryset = Outage.objects.filter(published = True)
The models.py is listed below.
from django.db import models
from django.contrib.auth.models import User
class Outage(models.Model):
outage_name = models.CharField(max_length=60, unique=True)
published = models.BooleanField()
def __unicode__(self):
return self.outage_name
class Detail(models.Model):
detail = models.CharField(max_length=60, unique=True)
user = models.ForeignKey(User)
outage = models.ForeignKey(Outage)
def __unicode__(self):
return self.outage
When I select from the list and submit the form I can't seem to figure out how to match outage = models.ForeignKey(Outage) that was selected on the list. To the correct outage_name. In my views.py I can hard code the id and it submits to the database and everything works fine.
def turnover_form(request):
if request.user.is_authenticated():
if request.method == 'POST':
form = TurnoverForm(request.POST)
if form.is_valid():
details = Detail.objects.get_or_create(
detail = form.cleaned_data['detail'],
user = request.user,
outage = Outage.objects.get(pk=1))
return HttpResponseRedirect('/turnover/user/')
else:
form = TurnoverForm()
variables = RequestContext(request, {'form': form})
return render_to_response('turnover_form.html', variables)
else:
return HttpResponseRedirect('/authorization/')
Any advice on how to match the id with the selected item would be appreciated. I'm sure my code is not very pythonic as I'm still learning.
outage = form.cleaned_data['outage'] # cleaned_data['outage'] is a model instance
Related
This is a very beginner-orientated question but I've been stuck on this issue all day.
I would like to load the data for a specific record and be able to save it (Submit button in a template) but i'm still trying to understand instances and the save method.
models.py
class model_essays(models.Model):
user = models.ForeignKey(User, default='1', on_delete=models.CASCADE)
title = models.CharField(max_length=100, default='')
date_added = models.models.DateTimeField(auto_now_add=True)
body = models.TextField()
def __str__(self):
return self.title
I understand the id is created automatically
forms.py
class frm_essays (forms.ModelForm):
class Meta:
model = model_essays
fields = ['title', 'date_added', 'body']
urls.py
urlpatterns = [
path('essay/<int:pk>', views.views_essay),
]
views.py {stuck here}
#login_required
def views_essay(request, pk):
if request.method == 'POST':
updatedForm = essay_detail(request.POST, instance=request.? {I want the ID of the essay})
if u_form.is_valid():
updatedForm.save()
messages.success(request, f'this essay has been updated')
return redirect('essay_detail')
else:
updatedForm = frm_essays(instance=request.{as above})
context = {
'updatedForm': updatedForm
}
return render(request, 'essay_detail.html', context)
On the decorator - I haven't gotten around to only allowing the users to view their own created essays, this would be the next large hurdle but not the issue I'm asking about.
Unless I am mistaken you are looking for the same ID as the pk (primary key). You have that passed in as an argument to your function.
You just need to query the instance from the DB.
def views_essay(request, pk):
essay = model_essays.objects.get(pk=pk)
if request.method == 'POST':
updatedForm = essay_detail(request.POST, instance=essay)
...
Note: essay will be None if the query based on the pk does not find an match in the DB.
I've created a Django view that does 2 things:
Create a new account
Modify a account
Works:
Creating new account and submitting the HTML form data to the database. Also works: showing a prefilled HTML form if user wants to modify an account with the account data that is known in the database.
Doesnt work:
When the user submits his/her form to update an account (user modified the info in the form), nothing is updated in the database.
I know how to update one single static value in the database like so:
a = accounts.objects.filter(pk=account_id).update(name='static value here')
but I don't know how to update the database with all the form data that the user submits when using Django Modelforms. Does anyone knows how to update the database with the submitted form data?
Code
#login_required(login_url='/dashboard/')
def dashboard_accounts_new_modify(request, account_id=None):
if request.method == 'POST':
# POST DETECTED
form = MyModelForm(request.POST, request.FILES)
if account_id:
# POST DETECTED
# ACCOUNT ID FOUND
# USER WANTS TO MODIFY A ACCOUNT
# WITH THIS QUERY I CAN UPDATE 1 STATIC VALUE IN THE DATABASE
# HOW DO I UPDATE THE VALUES FROM THE FORM IN THE DATABASE?? :(
a = accounts.objects.filter(pk=account_id).update(name='static value here')
return HttpResponseRedirect('/dashboard/accounts/')
else:
# POST DETECTED
# ACCOUNT ID NOT FOUND
# USER WANTS TO CREATE A NEW ACCOUNT
if form.is_valid():
if request.POST.get("name").lower() == 'new':
raise Http404("New account name may not be named NEW.")
# DATAHASE QUERY: ADD NEW ACCOUNT TO DATABASE
form.save()
# REDIRECT
return HttpResponseRedirect('/dashboard/accounts/')
elif account_id:
# NO POST DETECTED
# ACCOUNT ID FOUND
# PREFILL FORM WITH DATA
try:
from django.forms.models import model_to_dict
a = accounts.objects.get(pk=account_id)
form = MyModelForm(initial=model_to_dict(a))
except:
raise Http404("Account not found.")
else:
# NO POST DETECTED
# MODIFICATION IS NOT DETECTED
# LOAD EMPTY FORM
form = MyModelForm()
return render(request, 'backend/base_accounts_new.html', {'Title': 'Accounts', 'form' : form})
Model
# Clientdatabase
class accounts(models.Model):
name = models.CharField(max_length=200)
url = models.CharField(max_length=200)
website_title = models.CharField(max_length=200)
website_h1_text = models.CharField(max_length=200)
website_h2_text = models.CharField(max_length=200)
website_search_text = models.CharField(max_length=200)
website_font = models.CharField(max_length=200)
website_footer_left = models.CharField(max_length=600)
website_footer_right = models.CharField(max_length=600)
website_color_code_search_button = models.CharField(max_length=200)
website_color_code_banner = models.CharField(max_length=200)
website_logo_height_pixels = models.PositiveIntegerField()
website_logo_width_pixels = models.PositiveIntegerField()
filepath_favicon = models.FileField()
filepath_logo_vector = models.FileField()
filepath_logo_normal = models.FileField()
filepath_background_1 = models.FileField()
filepath_background_2 = models.FileField(blank=True, null=True)
filepath_background_3 = models.FileField(blank=True, null=True)
filepath_background_4 = models.FileField(blank=True, null=True)
setting_background_1_active = models.BooleanField()
setting_background_2_active = models.BooleanField()
setting_background_3_active = models.BooleanField()
setting_background_4_active = models.BooleanField()
def __str__(self):
return self.name
class AccountsForm(ModelForm):
class Meta:
model = accounts
fields = '__all__'
You can do like:
from django.shortcuts import get_object_or_404
if request.method == 'POST':
if account_id::
account = get_object_or_404(accounts, pk=account_id)
form = MyModelForm(request.POST,request.FILES, instance=account)
if form.is_valid():
...
form.save()
return HttpResponseRedirect('/dashboard/accounts/')
else:
form = MyModelForm(request.POST, request.FILES)
if form.is_valid():
if request.POST.get("name").lower() == 'new':
raise Http404("New account name may not be named NEW.")
form.save()
Learn more about forms here
I'm stuck on a problem with Django framework. In detail, user can create a Group and associate Member (>=1 && <=3) to the group. Each member is identified by email address (unique). However, the same member can partecipate with different name and surname in different groups. So I have a many to many relationship (using through) between Group and Member.
In my view I've an inlineformset. However when I submit the form I always get:
archi_groupmember.group_id may not be NULL
I've changed the widget for the MemberGroup form, because the user don't have to select a member from a select but he has to type the member's mail.
So I think I should persist the member just before to save the MemberGroup, but I don't know how to do it!
I'm totally new to Django, I'm following the docs.
Thank you all for any help!!
Here a page screenshot just to clarify: http://postimg.org/image/bndh5ug29/
Following my code.
Models.py:
class Group(models.Model):
user = models.ForeignKey(User)
limit = Q(active = True)
project = models.ForeignKey(Project, limit_choices_to = limit)
name = models.CharField(max_length=100)
code = models.CharField(max_length=100, unique=True)
def __unicode__(self):
return self.name
class Member(models.Model):
groups = models.ManyToManyField(Group, through='GroupMember')
email = models.EmailField(max_length=254, unique=True)
def __unicode__(self):
return self.email
class GroupMember(models.Model):
group = models.ForeignKey(Group)
member = models.ForeignKey(Member)
name = models.CharField(max_length=100)
surname = models.CharField(max_length=100)
views.py:
#login_required
#user_passes_test(first_login_check, login_url='/detail')
def partecipate(request):
from django.forms import TextInput
MemberFormSet = inlineformset_factory(Group, Member.groups.through, form=GroupMemberForm, can_delete=False, extra=3, widgets={'member': TextInput() } )
if request.method == 'POST':
form = GroupForm(request.POST)
member_set = MemberFormSet(request.POST)
if form.is_valid():
for form in member_set:
print vars( form['member'] )
group = form.save(commit=False)
group.user = request.user
group.code = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(10))
group.save()
member_set = MemberFormSet(request.POST, instance=group)
member_set = member_set.save(commit=False)
payment = Payment()
payment.group = group
payment.invoice = _createInvoice(group.project.id, group.id)
payment.save()
return HttpResponseRedirect("/")
else:
return render(request, "partecipate.html", { 'form': form, 'member_set' : member_set })
else:
form = GroupForm()
form.Meta.model.project.queryset = Project.objects.filter(active=True)
member_set = MemberFormSet(initial=[ {'name': request.user.first_name,'surname': request.user.last_name,'member':request.user.email} ])
return render(request, "partecipate.html", { 'form': form, 'member_set' : member_set })
What version of Django are you using?
Since 1.3 the help docs has an example of using inlineformset_factory. And the example (link below) clearly shows passing in an instance of the parent record. Without that, your formsets will not be linked to real data.
https://docs.djangoproject.com/en/1.7/topics/forms/modelforms/#using-an-inline-formset-in-a-view
I'm also suspicious of specifying the Member.groups.through table class as the child. I would think you should leave it as Member, because the through table is part of the internal machinery.
I have question regarding how to attach additional form to logged in users in Django.
I want that additional form belongs to logged in user and the data I enter in the form should goes under logged in user table. I am new to Django and python please have patience I hope i can explain correctly what i want to do with this
Data I shall enter for this view shall go under logged in user only basically i want to attach this view to the logged in user only Error I am getting is
Exception Value:
registration_todos.user_id may not be NULL
#models
class userProfile(models.Model):
user = models.OneToOneField(User)
birth =models.DateField()
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class todos(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=100)
created = models.DateField()
time = models.TimeField()
def __unicode__(self):
return unicode(self.user)
#forms additional form for todos
class formtodos(ModelForm):
title = forms.CharField(label=(u'Todo'))
created = forms.DateField(label=(u'Date'))
time = forms.TimeField(label=(u'Time'))
#user = forms.CharField(label=(u'username'))
class Meta:
model = todos
exclude=('user',)
#view
def modeltodo(request):
if request.user.is_authenticated():
todos.objects.filter(user=request.user)
if request.method == 'POST':
form =formtodos(request.POST)
if form.is_valid():# All validation rules pass
todoss = form.save(commit=False)
todoss.created_by = request.user
form.save()
return HttpResponseRedirect('/profile/')
else:
form = formtodos() # An unbound form
context = {'form':form}
return render_to_response('todo.html', context, context_instance=RequestContext(request))
you've specified exclude = ('user',) in your form. This means that when you try to save the form there is no user_id present which causes the error. You probably want to put this before the save() call: todoss.user = request.user
I am writing a simple form in Django which includes a ChoiceField allowing users to choose from a list of categories. For sure I want to pass the category_id to be processed. This is my code:
models.py:
class Category(models.Model):
category = models.CharField(max_length=128)
def __unicode__(self):
return self.category
class Product(models.Model):
code = models.CharField(max_length=75)
name = models.CharField(max_length=128)
price = models.DecimalField(max_digits=7, decimal_places=2)
category = models.ForeignKey(Category)
def __unicode__(self):
return self.name
forms.py
class AddProductForm(forms.Form):
category = forms.ChoiceField(label=_('Category'))
product = forms.CharField(label=_('Product'), widget=forms.TextInput())
code = forms.CharField(label=_('Code'), widget=forms.TextInput())
price = forms.DecimalField(label=_('Price'))
Now in the views.py I fill in the choices:
def add_product_form(request):
form = AddProductForm()
form.fields['category'].choices =[(c.id, c.category) for c in Category.objects.all()]
return render_to_response('product-form.html', {'form':form})
Now everything seems to be okay except when I submit the form. It complains about the IDs of the Category. It says:
Select a valid choice. 1 is not one of the available choices
This is how I am processing the form:
def add_product(request):
if request.method == 'POST':
form = AddProductForm(request.POST)
if form.is_valid():
category = request.cleaned_data['category']
product = form.cleaned_data['product']
code = form.cleaned_data['code']
price = form.cleaned_data['price']
product = Product(code=code, name=product, price=price, category_id=category)
product.save()
return HttpResponseRedirect('/ms-admin/')
else:
form = AddProductForm() # more is required here to fill the choices again
return render_to_response('product-form.html', {'form':form})
I tried the same with TypedChoiceField but got the same invalid data. I know it has to do with the conversion between string and int and the unicode stuff. Can you please explain?
For some reason, you've separated the view that renders the form - including adding the choices - and the view that processes the submission. You don't add the choices on submission, so of course the values are not going to be valid.
You should get rid of the add_product_form view altogether. You could move the form.fields['category'].choices... bit into the add_product view, but a better solution is to use the form field that's specifically designed for getting choices from a model or queryset - ie ModelChoiceField.
Just use:
category = forms.ModelChoiceField(model=Category)
in your form definition.
Thanks Daniel. I started learning Django not long time ago and I have this tendency to add a view to display a form, which is not necessary. So yes, I got rid of add_product_form and relied solely on add_product. As for the Category choice field now it is coded like this in the forms.py:
forms.py:
from django import forms
from django.utils.translation import ugettext_lazy as _
from myapp.models import Category
class AddProductForm(forms.Form):
category = forms.ModelChoiceField(label=_('Category'), queryset=Category.objects.all())
product = forms.CharField(label=_('Product'), widget=forms.TextInput())
code = forms.CharField(label=_('Code'), widget=forms.TextInput())
price = forms.DecimalField(label=_('Price'))
views.py:
def add_product(request):
if request.method == 'POST':
form = AddProductForm(request.POST)
if form.is_valid():
category = request.POST['category']
product = form.cleaned_data['product']
code = form.cleaned_data['code']
price = form.cleaned_data['price']
product = Product(code=code, name=product, price=price, category_id=category)
product.save()
# redirect to 'ms-admin/category_id' (the category to which belongs the newly added product
return HttpResponseRedirect('/ms-admin/'+category)
else:
form = AddProductForm()
return render_to_response('product-form.html', {'form':form})
I hope this helps newcomers to django. Please feel free to mention any ways of improving this above code ...