So I have a ManageUserForm in forms.py-- it renders correctly but it doesn't pull the right data from the user i'm trying to edit.
In the template, I have a for loop that works correctly
{% for tenants in tenants %}
{{ tenants.user }} {{ tenants.type }}
{% endfor %}
This template renders the list of objects in the UserProfile. And it does it correctly. The challenge I face is updating the "tenants.type" attribute. Again, the type shows up correctly but I don't know how to update it from this template page.
#views.py
def manage_users(request):
tenants = UserProfile.objects.all()
form = ManageUserForm(request.POST or None)
if form.is_valid():
update = form.save(commit=False)
update.save()
return render_to_response('manage_users.html', locals(), context_instance=RequestContext(request))
#forms.py
class ManageUserForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ('full_name', 'user',)
`I think I need to call an instance but I have no idea how to do so for the non-request users AND still follow the pattern for the template. The template basically is a list of users where the request user (staff user) will be able to change the data in the list.
Thank you for your help!
You have one form for one user. You need a FormSet if you want to use that form to edit multiple tenants. Editing objects and displaying them are entirely different beasts; dont' confuse them.
formset = modelformset_factory(form=ManageUserForm, queryset=tenants)
Update:
You should have one {{ form.management_form }} and the rest of the {% for form in formset %}{{ form }}{% endfor %} in one <form> tag. All of your forms are the first form in the formset.
You should rewrite your template loop to iterate through formset forms instead of tenant objects. The tenant object can be accessed through {{ form.instance }}
Update 2:
You have an extra form because you probably haven't passed in the extra=0 parameter to the modelformset_factory function. These forms are typically used to add/edit data; thus it has support for adding N blank forms for creating.
Related
I'm using inline formsets in Django, and for each item showing one "extra" form, for adding another object.
The forms for existing objects have "Delete" checkboxes, for removing that object, which makes sense.
But also the "extra" forms have these "Delete" checkboxes... which makes no sense because there's nothing there to delete. Inline forms in the Django admin don't show these "Delete" checkboxes for "extra" forms.
How can I remove these checkboxes on the "extra" inline forms?
The inline formsets part of my template is something like this (simplified, full version on GitHub):
{% for bookimage_form in form.forms %}
{% for hidden_field in bookimage_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
{{ bookimage_form.as_table }}
{% endfor %}
And here's the "Delete" checkbox that seems superfluous:
You can use the can_delete setting of the InlineModelAdmin class (TabularInline inherits from InlineModelAdmin):
class BookImageInline(admin.TabularInline):
model = BookImage
extra = 1
can_delete = False
Update for Django 3.2+ (link), you can now pass in can_delete_extra as False to formset_factory or it extended classes to remove checkbox from extra forms
can_delete_extra New in Django 3.2.
BaseFormSet.can_delete_extra
Default: True
While setting can_delete=True, specifying can_delete_extra=False will
remove the option to delete extra forms.
For anyone having Django version under 3.2 and do not wish to upgrade, please use the following method of overriding the BaseFormSet:
class CustomFormSetBase(BaseModelFormSet):
def add_fields(self, form, index):
super().add_fields(form, index)
if 'DELETE' in form.fields and form.instance.pk: # check if have instance
form.fields['DELETE'] = forms.BooleanField(
label=_('Delete'),
widget=forms.CheckboxInput(
attrs={
'class': 'form-check-input'
}
),
required=False
)
else:
form.fields.pop('DELETE', None)
YourFormSet = modelformset_factory(
formset=CustomFormSetBase,
can_delete=True,
extra=2
)
only took them 13 years to add this >.> https://code.djangoproject.com/ticket/9061
I found a way to remove the delete checkbox in the official django documentation here
you just have to add 'can_delete=false' as an argument to inlineformset_factory in your views.py file
inlineformset_factory(can_delete=false)
here's a way to get there in the template when you're looping through forms:
{% if bookimage_form.instance.pk %}
<small><b>{{ bookimage_form.DELETE.label_tag }}</b></small><br>
{{ bookimage_form.DELETE}}
{% else %}
{% endif %}
you won't be able to use the as_table() method I don't think, though. You'll have to express every other field in the form.
Here's another thing you could try out after you initialise the form, but before it goes into the context:
for f in form.forms:
if not f.instance.pk:
f.fields['DELETE'] = None
Not sure how that'll come out in the table, but you may be able to monkey with the idea.
My suggest is to render the template in nested for loops and add this:
{% if forloop.parentloop.last and forloop.last%}
not render form filds
{% else %}
render field
{% endif %}
I am trying to pull data from two models within a DetailsView template (in Django). There is of course a primary model (eg. Articles) associated with the view, which is easy to access. However, I want to access data from a model (eg. Terms). I do not want to use ForeignKey because I will be using many 'Terms' in each 'Article,' and since ForeignKey will allow me to link to only row in the Terms model, I will have to set-up mutiple ForeignKey fields, which can get messy fast.
I was thinking that this could be accomplished using get_context_data or templatetags, but haven't have had any luck yet. Any thoughts?
From Django Documentation you can add any queryset or context value you like to call in your template context like book_list below will list all books and it doesn't has to be linked with any other models..
#views.py
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
#yourtemplate.html
{% for book in book_list %}
{% if book %}
{{ book.title }}
{% endif %}
{% empty %}
No book_list found.
{% endfor %}
I'm learning Django Framework, and I have a question. To help you understand I will try and explain using the example below:
Suppose that we have some table in db as is:
CREATE TABLE names (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100));
And I have the form in Django Admin as is:
<form>
<textarea name="names"></textarea>
<input type="submit" name="sbt" value="Submit">
</form>
User entered something in the input names in the form and submitted it. Then a script catches this data and splits it into an array (str.split("\n")) and in cycle adding to table names!
And I many quetion:
How i can add form to Django Admin?
How i can catch form data and add this data to somethink table in database?
Thanks.
First of all you must create a django model.
Put this code in models.py.
class Names(models.Model):
name = models.CharField(max_length = 100)
Then you must create the admin model.
Put this code in admin.py.
class NamesAdmin(admin.ModelAdmin):
list_display = ['name']
# whatever you want in your admin panel like filter, search and ...
admin.site.register(Names, NamesAdmin)
I think it meet your request. And for split the names you can override save model method and split the names in there. But if you want to have an extra form, you can easily create a django model form.
Put the code somewhere like admin.py, views.py or forms.py
class NamesForm(forms.ModelForm)
class Meta:
model = Names
That's your model and form. So, if your want to add the form to django admin panel you must create a view for it in django admin. For do this create a view as common.
Put the code in your admin.py or views.py.
def spliter(req):
if req.method == 'POST':
form = NamesForm(req.POST)
if form.is_valid():
for name in form.cleaned_data['names'].split(' '):
Names(name = name).save()
return HttpResponseRedirect('') # wherever you want to redirect
return render(req, 'names.html', {'form': form})
return render(req, 'names.html', {'form': NamesForm()})
Be aware you must create the names.html and put the below code in you html page.
{% extends 'admin/base_site.html' %}
{% block content %}
<!-- /admin/names/spliter/ is your url in admin panel (you can change it whatever you want) -->
<form action="/admin/names/spliter/" method="post" >{% csrf_token %}
{{ form }}
<input type="submit" value="'Send'" >
</form>
{% endblock %}
This is your view and your can use it everywhere. But if you want only the admin have permission to see this page you must add this method too your NamesAdmin class.
def get_urls(self):
return patterns(
'',
(r'^spliter/$', self.admin_site.admin_view(spliter)) # spliter is your view
) + super(NamesAdmin, self).get_urls()
That's It. I hope this can help you.
I am iterating over a formset made of modelforms in my template. I want to provide aditional information on that model. If the answer to this How to Access model from Form template in Django question would work, i could do this:
{% for form in formset.forms %}
Status:{{ form._meta.model.status }}
{{form}}
{% endfor %}
But that just throws the TemplateSyntaxError: Variables and attributes may not begin with underscores.
I don't think that's what you want to do. A model is a class: it won't have a status, as that's a field which only gets a value for a particular instance.
I suspect what you mean to do is access the model instance associated with the form, which is just form.instance.
If you create a property on the form that reads the value then you can access it very easily in the template.
class SomeForm(...):
#property
def status(self):
return self._meta.model.status
...
{{ form.status }}
I'm new to Django and I'm creating an app to create and display employee data for my company.
Currently the model, new employee form, employee table display, login/logout, all works. I am working on editing the current listings.
I have hover on row links to pass the pk (employeeid) over the url and the form is populating correctly- except the manytomanyfields are not populating, and the pk is incrementing, resulting in a duplicate entry (other than any data changes made).
I will only put in sample of the code because the model/form has 35 total fields which makes for very long code the way i did the form fields manually (to achieve a prettier format).
#view.py #SEE EDIT BELOW FOR CORRECT METHOD
#login_required
def employee_details(request, empid): #empid passed through URL/link
obj_list = Employee.objects.all()
e = Employee.objects.filter(pk=int(empid)).values()[0]
form = EmployeeForm(e)
context_instance=RequestContext(request) #I seem to always need this for {%extend "base.html" %} to work correctly
return render_to_response('employee_create.html', locals(), context_instance,)
#URLconf
(r'^employee/(?P<empid>\d+)/$', employee_details),
# snippets of employee_create.html. The same template used for create and update/edit, may be a source of problems, they do have different views- just render to same template to stay DRY, but could add an additional layer of extend for differences needed between the new and edit requests EDIT: added a 3rd layer of templates to solve this "problem". not shown in code here- easy enough to add another child template
{% extends "base.html" %}
{% block title %}New Entry{% endblock %}
{% block content %}
<div id="employeeform">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="/newemp/" method="post" class="employeeform">{% csrf_token %} #SEE EDIT
<div class="left_field">
{{ form.employeeid.value }}
{{ form.currentemployee.errors }}
<label for="currentemployee" >Current Employee?</label>
{{ form.currentemployee }}<br/><br/>
{{ form.employer.errors }}
<label for="employer" class="fixedwidth">Employer:</label>
{{ form.employer }}<br/>
{{ form.last_name.errors }}
<label for="last_name" class="fixedwidth">Last Name:</label>
{{ form.last_name }}<br/>
{{ form.facility.errors }} #ManyToMany
<label for="facility" class="fixedwidth">Facility:</label>
{{ form.facility }}<br/><br/>
</div>
<div id="submit"><br/>
<input type="submit" value="Submit">
</div>
</form>
#models.py
class Employee(models.Model):
employeeid = models.AutoField(primary_key=True, verbose_name='Employee ID #')
currentemployee = models.BooleanField(null=False, blank=True, verbose_name='Current Employee?')
employer = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
facility = models.ForeignKey(Facility, null=True, blank=True)
base.html just has a header on top, a menu on the left and a big empty div where the forms, employee tables, etc all extend into.
screenshot2
So, how do I need to change my view and/or the in the template to update an entry, rather than creating a new one? (
And how do I populate the correct foriegnkeys? (the drop down boxes have the right options available, but the "-----" is selected even though the original database entry contains the right information.
Let me know if i need to include some more files/code
I have more pics too but i cant link more or insert them as a new user :< I'll just have to contribute and help out other people! :D
EDIT:
I've been working on this more and haven't gotten too far. I still can't get the drop-down fields to select the values saved in the database (SQLite3).
But the main issue I'm trying to figure out is how to save as an update, rather than a new entry. save(force_update=True) is not working with the default ModelForm save parameters.
views.py
def employee_details(request, empid):
context_instance=RequestContext(request)
obj_list = Employee.objects.all()
if request.method == 'POST':
e = Employee.objects.get(pk=int(empid))
form = EmployeeForm(request.POST, instance=e)
if form.is_valid():
form.save()
return HttpResponseRedirect('/emp_submited/')
else:
e = Employee.objects.get(pk=int(empid))
form = EmployeeForm(instance=e)
return render_to_response('employee_details.html', {'form': form}, context_instance,)
also changed template form action to "" (from /newemp/ which was the correct location for my new employee tempalte, but not the update.
Thanks to this similar question.
updating a form in djnago is simple:
steps:
1. extract the previous data of the form and populate the edit form with this these details to show to user
2. get the new data from the edit form and store it into the database
step1:
getting the previous data
views.py
def edit_user_post(request, topic_id):
if request.method == 'POST':
form = UserPostForm(request.POST)
if form.is_valid():
#let user here be foreign key for the PostTopicModel
user = User.objects.get(username = request.user.username)
#now set the user for the form like: user = user
#get the other form values and post them
#eg:topic_heading = form.cleaned_data('topic_heading')
#save the details into db
#redirect
else:
#get the current post details
post_details = UserPostModel.objcets.get(id = topic_id)
data = {'topic_heading':topic.topic_heading,'topic_detail':topic.topic_detail,'topic_link':topic.topic_link,'tags':topic.tags}
#populate the edit form with previous details:
form = UserPostForm(initial = data)
return render(request,'link_to_template',{'form':form})