Django ModelFormset name instead of ID in foreign key field - python

I'm having a problem with modelformset custom field so to speak. This is the code so far and it works fine:
models.py:
class Workplace(models.Model):
user = models.ForeignKey(User)
description = models.TextField(blank=True, null=True)
organization = models.ForeignKey(Organization)
position = models.CharField(max_length=250, null=True)
start = models.DateTimeField(null=True, blank=True)
end = models.DateTimeField(null=True, blank=True)
place = models.ForeignKey(Place, null=True, blank=True)
deleted = models.BooleanField(default=False)
forms.py:
class UserWorkplaceForm(forms.ModelForm):
class Meta:
model = Workplace
labels = {
'deleted': 'Delete this position'
}
def __init__(self, *args, **kwargs):
super(UserWorkplaceForm, self).__init__(*args, **kwargs)
self.fields['position'].required = True
self.fields['organization'].required = True
self.fields['start'].required = True
views.py:
def settings_workplace(request):
workplace_formset = modelformset_factory(Workplace,
form=UserWorkplaceForm,
fields=('user', 'position', 'organization', 'start', 'end', 'deleted'),
widgets={'user': forms.HiddenInput(),
'start': forms.DateInput(attrs={'class': 'workplace-date'}),
'end': forms.DateInput(attrs={'class': 'workplace-date'}),
'deleted': forms.CheckboxInput(),
'organization': forms.TextInput()
},
extra=0)
if request.method == "POST":
formset = workplace_formset(request.POST)
if formset.is_valid():
formset.save()
formset = workplace_formset(queryset=request.user.get_profile().workplace.filter(deleted=False))
else:
formset = workplace_formset(queryset=request.user.get_profile().workplace.filter(deleted=False))
context = {
'formset': formset
}
return render_to_response('accounts/settings_workplaces.html', context, RequestContext(request))
The 'organization' field is rendered as a Select HTML element. I can't have that because there are thousands of organizations in the database. What I'd like to do is display the Organization as a text field. That's what I did in the widgets part. However, that gives me the ID of the field, normally, not the name.
Is there a way for me to get both? I need the name for a nicer display and I need the ID in case editing happens (on a different field) because that field is required.
Any ideas?

Can you make it a ChoiceField where the 1st value is the ID of Organization, and the 2nd value is the Human Readable name of the Organization? That is my recommendation to handle this situation. Here is the documentation on setting 'choices' in Django:
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#choicefield
https://docs.djangoproject.com/en/1.7/ref/models/fields/#choices

Related

How to update only selected records in Django queryset like in admin panel actions? [duplicate]

I need to update the model according to the marked checkboxes in the django shape
How can I get only some of the table fields in a query
the "checked" line should be updated through the queryset
models.py
class moIn(models.Model):
date = models.DateTimeField(auto_now_add=True, verbose_name='')
dateUpdate = models.DateTimeField(auto_now=True)
ts = models.IntegerField(verbose_name='')
pl = models.IntegerField(verbose_name='')
rem = models.IntegerField(verbose_name='')
comment = models.TextField(max_length=200, verbose_name='', blank=True)
staffer = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name='')
checked = models.BooleanField(verbose_name='', default=False)
checkedUser = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name='', blank=True, null=True, related_name='checkedUser')
by clicking this checkbox, you will need to receive database records
forms.py
class checkForm(ModelForm):
checked = fields.BooleanField(required=False)
class Meta:
model = moIn
fields = {"id", "checked"}
views.py
def dashboard(request):
if request.user.groups.filter(name='DashBoardAccess').exists():
form = checkForm
f = tableDashFilter(request.GET, queryset=moIn.objects.all())
if request.method == 'POST':
form = checkForm(request.POST)
if form.is_valid():
tt = form.save(commit=False)
data = form.cleaned_data
field = data['checked']=True
f.qs.filter(checked=field).update(checked=True, checkedUser=request.user)
return HttpResponse('ok')
else:
context = {
'filter': f,
'form': form
}
return render(request, 'dashboard/index.html', context)
else:
raise Http404()
in a line in bold, you need to get only those lines in which the checkbox is marked
f.qs.filter(checked=field).update(checked=True, checkedUser=request.user)
You can get all the fields using ".values ()" for the queryset, and to use it with foreignKey, you need to explicitly specify the model fields:
f = tableDashFilter(request.GET, queryset=moIn.objects.values('id','date','ts','pl','rem','comment','checked','staffer__username','checkedUser__username'))
"Value" from the input, it is also going to be obtained through:
Since there can be several values (marked checkboxes), there will be a ".getlist"
checkID = request.POST.getlist('checked')
querySet filter:
f.qs.filter(id__in=checkID).update(checked=True, checkedUser=request.user)
in the html template through the loop, iterate over and insert into the input value of the model id

Update field in db in django from views with existing form, won't update because of "Integrity Error"

My first post, really newbie at programming. I am having issues to update a field in a form. I'll try to explain my best.
I have a Catalog class (products or services) with a couple fields, 2 of them must be unique.
models.py
class Catalogo(models.Model):
item = models.CharField(
max_length=100, help_text="Product or service name", unique=True
)
sku = models.CharField(max_length=50, help_text="Part Number", unique=True)
category = models.CharField(
max_length=15, choices=categoria, verbose_name="Category"
)
description = models.CharField(
max_length=200,
help_text="Item description",
verbose_name="Descripción",
)
created = models.DateTimeField(auto_now_add=True, help_text="Created")
updated = models.DateTimeField(auto_now_add=True, help_text="Updated")
active = models.BooleanField(default=True)
class Meta:
verbose_name = "product and service"
verbose_name_plural = "products and services"
def __str__(self):
return self.item
Then i have a form to gather the information
forms.py
categories = [("Product", "Product"), ("Service", "Service")]
class NewProductForm(forms.Form):
item = forms.CharField(
widget=forms.TextInput(attrs={"class": "form-control"}),
label="Item",
max_length=100,
)
sku = forms.CharField(
widget=forms.TextInput(attrs={"class": "form-control"}),
label="Part number",
max_length=50,
)
category = forms.ChoiceField(
choices=categories,
label="Category",
)
description = forms.CharField(
widget=forms.Textarea(attrs={"class": "form-control"}),
label="Item description",
)
Now for the views...i created 2 functions, one for adding new product/service and one for updating
views.py
def new_prod_serv(request):
new_form = NewProductForm()
if request.method == "POST":
new_form = NewProductForm(request.POST)
if new_form.is_valid():
new_product = Catalogo(
item=new_form["item"].value(),
sku=new_form["sku"].value(),
category=new_form["category"].value(),
description=new_form["description"].value(),
)
new_product.save()
return redirect("products-services")
else:
print(new_form.errors)
context = {"formulario": new_form}
return render(request, "SkytechnosaApp/comercial/nuevoproducto.html", context)
def update_prod_serv(request, primarykey):
product_service = Catalogo.objects.get(id=primarykey)
item = product_service.item
sku = product_service.sku
category = product_service.category
description = product_service.description
form_data = {
"item": item,
"sku": sku,
"category": category,
"description": description,
}
form = NewProductForm(initial=form_data)
if request.method == "POST":
form = NewProductForm(request.POST, initial=form_data)
if form.is_valid():
form.save()
return redirect("products-services")
else:
print(form.errors)
context = {"form": form}
return render(request, "SkytechnosaApp/comercial/nuevoproducto.html", context)
The html works okay, the problem i'm facing is when i click on edit...it will populate the form with the information of the product or service i want to edit (that's fine), but then i make the changes on the comment field for example (just want to update comment) and then I get the error IntegrityError at /comercial/productos/nuevo
UNIQUE constraint failed: Comercial_catalogo.sku
It's like it's trying to create another product, because when i go back and i edit all the fields, and click on save, i see another product created, but I just wanted to update, rather than create a new product....what i am missing?
Thank you!
Your form code you pasted in your question is not complete (it's just a form.Form not a form.ModelForm, and yet you called form.save())
forms.py
class NewProductForm(forms.ModelForm):
item = forms.CharField(
widget=forms.TextInput(attrs={"class": "form-control"}),
label="Item",
max_length=100,
)
sku = forms.CharField(
widget=forms.TextInput(attrs={"class": "form-control"}),
label="Part number",
max_length=50,
)
category = forms.ChoiceField(
choices=categories,
label="Category",
)
description = forms.CharField(
widget=forms.Textarea(attrs={"class": "form-control"}),
label="Item description",
)
class Meta:
model = Catalogo
After that, if you want to update an instance (instead of creating one), you have to tell the ModelForm which instance it has to update:
view.py
def update_prod_serv(request, primarykey):
...
instance = Catalogo.objects.get(id=primarykey)
if request.method == 'POST':
form = NewProductForm(request.POST, instance=instance) # you don't need to use `initial` since
if form.is_valid():
form.save()
...
That said, it's generally best to have just ONE view for creating and updating. If you want to see how that works let me know.

Django 3 - Making Model's FK Dropdown Display Current User's Data Only

I'm creating my first app with Django and still have a lot to learn, but right now I am completely stuck and need some help. I have a model for Customers and Tickets. I have it so different users can save new customers/tickets and only view their data from the dashboard once logged in. However, when creating a new ticket, there is a dropdown option to select customer for the ticket - and the current user is able to see every users customers.
Here is the code, I'll share more code if needed, but I think this covers what I have going on...
forms.py
class TicketForm(ModelForm):
class Meta:
model = Ticket
fields = ['number', 'customer','date_created','work_description','mechanics','status']
views.py
def createTickets(request):
form = TicketForm()
if request.method == 'POST':
form = TicketForm(request.POST)
if form.is_valid():
newticket = form.save(commit=False)
newticket.shopowner = request.user
newticket.save()
return redirect('tickets')
context = {
'form': form
}
return render(request, 'createticket.html', context)
models.py
class Ticket(models.Model):
def default_number():
no = Ticket.objects.count()
return no + 1
shopowner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
number = models.CharField(max_length=30, unique=True, default= default_number)
customer = models.ForeignKey(Customer, default=1, on_delete= models.SET_DEFAULT, blank=True)
date_created = models.DateField(default=timezone.now)
work_description = models.TextField(verbose_name="Service Details: ")
mechanics = models.ForeignKey(Mechanic, default=1, on_delete=models.DO_NOTHING, blank=True, verbose_name="Mechanic")
status = models.BooleanField(default=True, verbose_name="Open Ticket")
class Meta:
verbose_name_plural = "Tickets"
I need the Customer foreignkey to only display customers of the current user (or 'shopowner') - same thing for mechanic and eventually vehicle but I can figure those out once I know how to get the customer input to display the correct data.
You'll need to customize your form a bit, in order to modify the queryset for that particular field. We also need to pass a user from the view:
forms.py
class TicketForm(ModelForm):
class Meta:
model = Ticket
fields = ['number', 'customer', 'date_created', 'work_description', 'mechanics', 'status']
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
if user:
self.fields['customer'].queryset = Customer.objects.filter(shopowner=user)
views.py
def createTickets(request):
form = TicketForm(user=request.user)
# ...
Exactly how you define the queryset is going to depend on how you've defined the relationship between Customer and Shopowner, but this should give you the right approach.

Django-, display and filter particular fields from a foreign key in a model form

I am using a model form, and the field is a foreign key, to another the model, the foreign key model contains a choice field(status) which i want filter based on user group,such that if a user belongs to a group, for example if the user in a group DEVELOPER, the status choices available will be 'Weekly Task' and 'Daily Task'
models.py
class ScrumyGoals(models.Model):
user_name=models.ForeignKey('ScrumyUser', on_delete= models.CASCADE, null= True)
status_id = models.ForeignKey('GoalStatus', on_delete=models.CASCADE,null=True)
goal_type = models.CharField(choices=GOAL_TYPE, max_length=64, default='DT')
def __str__(self):
return '{},{}'.format(self.user_name,self.status_id)
class GoalStatus(models.Model):
GOALS_TYPE= (('DT','Daily Task'),
('WT','Weekly Task'),
('V','Verified'),
('D','Done'),
)
title = models.CharField(max_length=254, null=True)
task_id=models.IntegerField(default=1,null=False)
description =models.CharField(max_length=254)
verified_by=models.ForeignKey('ScrumyUser', on_delete= models.CASCADE, null=True)
status=models.CharField(choices=GOALS_TYPE, max_length=2, default='DT')
forms.py
class ChangeTaskForm(forms.ModelForm):
class Meta:
model = ScrumyGoals
fields = ['status_id']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(ChangeTaskForm, self).__init__(*args, **kwargs)
if user.groups.filter(name ='DEVELOPER').exists():
self.fields['status'].choices = (('WT','Weekly Task'), ('DT','Daily Task'),)
views.py
def changetask(request):
if request.method == 'POST':
form = ChangeTaskForm(request.POST, user=request.user)
if form.is_valid():
return HttpResponseRedirect('/index/')
else:
form = ChangeTaskForm(user=request.user)
return render(request, 'oderascrumy/changetask.html', {'form': form})
The form only currently shows the status_id , it doesn't show the choices (ie "status")
so in essence what i want is this if the logged in user is in group say "DEVELOPER", The user can only change the goal (ie "status_id") choice (ie "status") from weekly task to daily task and the form is saved
Does it work if you remove the if from forms.py, i.e. are you positive the Group with name 'DEVELOPER' exists, and that the user you're testing with is actually in that group?
An alternative might be to always include status in fields, then just conditionally show that field in the template with if user.groups in ['DEVELOPER'].

many to many field in django is working in admin site but not in front end site form

In my code CreateNoticeForm is working fine and all data gets saved perfectly except
many to many field which is tags in my notice model.Although it is working on admin site and gets saved.
here is my code
models.py
from django.db import models
from django.contrib.auth.models import User
from wysihtml5.fields import Wysihtml5TextField
# Create your models here.
class Tag(models.Model):
# For notice tags
name = models.CharField(max_length=70, unique=True)
def __str__(self):
return self.name
class Notice(models.Model):
# Notice Store
headline = models.CharField(max_length=140)
description = Wysihtml5TextField()
file_name = models.FileField(upload_to='static/noticefiles/', blank=True)
created_by = models.ForeignKey(User)
fors = models.CharField(max_length=1, choices=(('F','Faculty'),('S','Student'),) )
last_date = models.DateField()
tags = models.ManyToManyField(Tag, blank=True)
post_time = models.DateTimeField(auto_now_add=True)
update_time = models.DateTimeField(auto_now=True)
def __str__(self):
return self.headline
forms,py
FORS_CHOICES = (('F','Faculty'),('S','Student'))
class CreateNoticeForm(ModelForm):
fors = forms.ChoiceField(label="Related To",
choices=FORS_CHOICES,
)
class Meta:
model = Notice
fields = ('headline', 'description',
'fors', 'last_date', 'tags','file_name')
widgets = {
'description': Wysihtml5BootstrapWidget(),
'last_date': SelectDateWidget()
}
def __init__(self, *args, **kwargs):
super(CreateNoticeForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'create_notice_form_id'
self.helper.form_class = 'form-horizontal'
self.helper.form_method = 'post'
self.helper.label_class = 'col-lg-2'
self.helper.field_class = 'col-lg-8'
self.helper.layout = Layout(
Fieldset('Create Notice',
'headline',
'description',
Field('fors', label='Audience'),
MultiWidgetField('last_date',
attrs=(
{'style': 'width: 33.33%; display: inline-block;'}
)
),
'tags',
'file_name',
FormActions(
Submit('save', 'Create Notice',
css_class='btn-warning col-lg-offset-2'),
),
),
views.py
def create_notice(request):
context = RequestContext(request)
posted = False
if request.method=='POST':
create_notice_form = CreateNoticeForm(data=request.POST, files=request.FILES)
if create_notice_form.is_valid():
cnf = create_notice_form.save(commit=False)
cnf.created_by = request.user
cnf.save()
posted = True
else:
print(create_notice_form.errors)
else:
create_notice_form = CreateNoticeForm()
return render_to_response('notices/createnotice1.html',
{'create_notice_form': create_notice_form,
'posted': posted,},
context)
You have to call save_m2m():
cnf = create_notice_form.save(commit=False)
cnf.created_by = request.user
cnf.save()
create_notice_form.save_m2m()
Excerpt from the documentation:
If your model has a many-to-many relation and you specify commit=False when you save a form, Django cannot immediately save the form data for the many-to-many relation. This is because it isn’t possible to save many-to-many data for an instance until the instance exists in the database.
To work around this problem, every time you save a form using commit=False, Django adds a save_m2m() method to your ModelForm subclass. After you’ve manually saved the instance produced by the form, you can invoke save_m2m() to save the many-to-many form data.
You have to Call the following after validating the form:-
if create_notice_form.is_valid():
parent = create_notice_form.save(commit=False)
parent.save()
create_notice_form.save_m2m()
I hope this will help you

Categories

Resources