Is it possible to include model form template in django admin as follows?
models.py
class Customer(models.Model):
name = models.CharField(max_length=20)
designation = models.CharField(max_length=20)
gender = models.BooleanField()
forms.py
class CustomerForm(forms.ModelForm)
gender = forms.TypedChoiceField(
choices=GENDER_CHOICES, widget=forms.RadioSelect(renderer=HorizontalRadioRenderer), coerce=int, )
class Meta:
model = Customer
template.html
<form action="{% url 'verinc.views.customerView' %}" method="POST">{% csrf_token %}
{{ form.as_p }}
<input id="submit" type="button" value="Click" /></form>
views.py
def customerView(request):
if request.method == 'POST':
form = CustomerForm(request.POST)
else:
form = CustomerForm()
return render_to_response('myapp/template.html', {'form' : form,})
admin.py
class CustomerInline(admin.StackedInline)
model= Customer
form = CustomerForm
template = 'myapp/template.html
When I view the form in url (localhost/myapp/customer) it displays all the fields correctly. But when I view it in admin page it displays only the submit button in the block. My requirement is to view the form using templates in admin page, so that i could use some AJAX script for further process. Any help is most appreciated.
Well , Its not possible . But you can implement like this :
You should create file called admin_views.py in your app customer.
Then add url in your urls.py like
(r'^admin/customer/customerView/$', 'myapp.customer.admin_views.customerView'),
Write your view implementation inside admin_views.py like :
from myapp.customer.models import Customer
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib.admin.views.decorators import staff_member_required
def customerView(request):
return render_to_response(
"admin/customer/template.html",
{'custom_context' : {}},
RequestContext(request, {}),
)
customerView = staff_member_required(customerView)
And inside your admin template extend base_site.html like this one :
{% extends "admin/base_site.html" %}
{% block title %}Custmer admin view{% endblock %}
{% block content %}
<div id="content-main">
your content from context or static / dynamic...
</div>
{% endblock %}
Thats it . hit that new url after admin login . Note Not Tested :) .
Related
I want to update User database using forms.When I trying to update it remains same the database and not update. So to perform this task ?
forms.py
from django import forms
from django.contrib.auth.models import User
class updateform(forms.ModelForm):
class Meta:
model=User
fields="__all__"
views.py
from django.contrib.auth.models import User
from .forms import updateform
#permission_required('is_superuser')#only superuser can update the data base
def upform(request,id):
emp=User.objects.get(id=id)
if request.method=='POST':
frm=updateform(request.POST,instance=emp)
if frm.is_valid():
frm.save()
return redirect('/')
else:
frm=updateform(instance=emp)
return render(request,'examp.html',{'frm':frm})
examp.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static '/examp.css' %}">
<style>
td,th{
border:1px solid;
text-align:center;
padding:10px;
}
</style>
</head>
<body>
{% include 'include/header.html' %}
<form action="/" method="POST">
{% csrf_token %}
{{ frm.as_p }}
<input type="submit" value="Submit">
</form>
</body>
</html>
How to update the database using this given form.
Why don't you use CBV generic views?
in yourapp/models.py:
from django.db import models
from django.urls import reverse
from django.contrib.auth import get_user_model
# const for get_absolute_url
#that's suffix will be using in your template names look at urls.py,
#if you need u should change it for smth here and in urls!
DETAIL_SUFFIX = '_detail'
class YourModel(models.Model):
name = models.CharField(default='new', max_length=6)
updated_by = models.ForeignKey(get_user_model(), on_delete=models.PROTECT,
related_name='get_upd_by_user')
def __str__(self):
return f'{self.name}'
def get_absolute_url(self):
return reverse(f'{self.__class__.__name__}{DETAIL_SUFFIX}', kwargs={"pk": self.pk})
You need to define the get_absolute_url method. Then reverse will works properly after you update.
in yourapp/views.py:
#views
from django.views.generic.edit import UpdateView
from django.views.generic import DetailView
# AAA
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
class ProjectSubnetDetailView(LoginRequiredMixin, DetailView):
model = YourModel
template_name = 'your_name_detail.html'
class YourNameUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
model = YourModel
template_name = 'your_name_edit.html'
fields = ('somefield', )
permission_required = ('yourapp.view_yourmodel','yourapp.change_yourmodel')
def form_valid(self, form): # Bind name of current user
form.instance.updated_by = self.request.user
return super().form_valid(form)
Instead of decorator #permission_required in CBV you can use PermissionRequiredMixin(I highly recommend reading about it in the official documentation). In short you must define only in this order:
(LoginRequiredMixin, PermissionRequiredMixin, UpdateView)
First - user must be Authenticated
Second - user must have a rights (or roles, that have a need rights)
Third - thats your generic view for do smth (in this example is update)
For second Attention You must specify in the view those rights that are checked before performing the update in strictly lowercase.
You can define rights in admin panel for some user or create a role and define some rights and add your user into that role. For example i create user and define him some rights for view and change table:
So if your model is called 'YourModel', you should specify 'action_yourmodel'
permission_required = ('yourapp.view_yourmodel','yourapp.change_yourmodel')
in yourapp/urls.py.
from django.urls import path
from .views import YourNameUpdateViewUpdateView, YourNameDetailView
urlpatterns = [
path('YourName/<int:pk>/edit/', YourNameUpdateView.as_view(), name='some_name_edit'),
path('YourName/<int:pk>/detail/', YourNameDetailView.as_view(), name='some_name_detail'),
]
in yourapp/templates/ you have to define 2 templates:
#your_name_detail.html
{% extends '_basetemplate.html' %}
{% block content %}
<div>
<p>{{ object.name }}</p>
</div>
<p>
Update |
</p>
{% endblock content %}
# your_name_edit.html
{% extends '_basetemplate.html' %}
{% block content %}
<h5>Updating {{ object.name }}</h5>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-sm btn-info ml-2" type="submit">Update</button>
</form>
{% endblock content %}
Good afternoon all,
One of my form does not seem to save when submitted. I cannot see why, in particular as I have a similar form working just fine using the same code.
For some reason it work just fine using the admin panel.
My assumption is that I am missing something that tells the form it needs to be saved. But cannot find what.
Any ideas?
Models
RATING=(
(1,'1'),
(2,'2'),
(3,'3'),
(4,'4'),
(5,'5'),
)
class ProductReview(models.Model):
user=models.ForeignKey(User, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="comments", on_delete=models.CASCADE)
review_text=models.TextField(max_length=250)
review_rating=models.IntegerField(choices=RATING,max_length=150, default=0)
date_added = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
Views
def add_review(request, product_id):
product = Product.objects.get(pk=product_id)
form = ReviewAdd(request.POST or None, instance=product) #instance=product (populate field with existing information)
if form.is_valid():
form.save()
return redirect('product')
return render(request, 'main/add_review.html',{'form':form})
URL
from django.urls import path
from . import views
urlpatterns = [
...
path('product/add_review/<product_id>', views.add_review,name="add_review"),
]
Forms
class ReviewAdd(forms.ModelForm):
class Meta:
model = ProductReview
fields = ('review_text', 'review_rating')
labels ={
'review_text': '',
'review_rating': '',
}
widgets = {
'review_text': forms.TextInput(attrs={'class':'form-control', 'placeholder':'Enter Review'}),
}
Admin
from django.contrib import admin
from .models import Venue, User, Product, ProductReview
from django.urls import path
admin.site.register(User)
admin.site.register(ProductReview)
class ProductReview(admin.ModelAdmin):
list_display=['user','product','review_text','get_review_rating']
HTML Page
{% extends 'main/base.html' %}
{% load crispy_forms_tags %}
{% block title %}
{% endblock %}
{% block content %}
<center>
<h1>Add ReviewTo Database</h1>
<br/><br/>
{% if submitted %}
Success!
{% else %}
<form action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="Submit" value="Submit" class="btn btn-secondary">
</form>
{% endif %}
</center>
{% endblock %}
I detect 2 fixes
On your url, the parameter product_id might need the type of data it will going to receive
path('product/add_review/<int:product_id>', views.add_review,name="add_review"),
And in your view, you are sending an instance, and no data for a new rating.
In your view:
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
#login_required
def add_review(request, product_id):
product = get_object_or_404(Product, pk=product_id)
form = ReviewAdd(request.POST or None)
if form.is_valid():
new_rating = form.save(commit=False)
new_rating.product = product
new_rating.user = request.user
new_rating.save()
return redirect('product')
return render(request, 'main/add_review.html',{'form':form})
In my app, I have created a context_proccessors.py to show the form to base.html file.
I am able to show the form in the base.html file. But the problem I am facing is I have no idea how to save that form data from base.html since there is no view for the base.html. Below is my code:
models.py
class Posts(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_posts')
post_pic = models.ImageField(upload_to='post_pic', verbose_name="Image")
post_caption = models.TextField(max_length=264, verbose_name="Caption")
created_date = models.DateTimeField(auto_now_add=True)
edited_date = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.user.username}"
forms.py
from django import forms
from post_app.models import Posts
class PostForm(forms.ModelForm):
class Meta:
model = Posts
exclude = ('user',)
context_proccessors.py
from post_app.forms import PostForm
def post_form(request):
form = PostForm
return {
'post_form': form,
}
base.html
<form method="POST" enctype="multipart/form-data">
{{ post_form|crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Post</button>
</form>
I want the form to be displayed on every page so that the user can submit data from anywhere
def PostView(request):
form = PostForm()
if request.method == 'GET':
return render(request, 'base.html', {form:form})
elif request.method == 'POST':
form.save(request.data)
In the views.py of your app you can define this view, and the you have to provide it an url in the urls.py of the root directory. So evere time there is a request on that url, if the method is GET, the form will be rendered on base.html file, if the method is POST, the post will be saved.
By following the answer by N T I have implemented this. So, I had to make a URL pattern for the view and use that URL pattern in the action in the form of base.html.
view.py
#login_required
def postsaveview(request):
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
user_obj = form.save(commit=False)
user_obj.user = request.user
user_obj.slug = str(request.user) + str(uuid.uuid4())
user_obj.save()
return HttpResponseRedirect(reverse('profile_app:profile'))
urls.py
urlpatterns = [
path('post-save/', views.postsaveview, name='post-save'),
]
base.html
<form action="{% url "post-save" %}" method="POST" enctype="multipart/form-data">
{{ post_form|crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Post</button>
</form>
I'm following the Wagtail documentation to customize the user model. I want to add an image to the user model.
Django version: 2.0.8,
Wagtail version: 2.1
Problem
After choosing an image with the image chooser field and clicking 'Save', this error shows up:
'No file was submitted. Check the encoding type on the form.'
Code
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
display_image = models.ForeignKey('wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+')
forms.py
from django import forms
from django.utils.translation import ugettext_lazy as _
from wagtail.users.forms import UserEditForm, UserCreationForm
from wagtail.images.widgets import AdminImageChooser
class CustomUserEditForm(UserEditForm):
display_image = forms.ImageField(
widget=AdminImageChooser(), label=_('Autorenbild'))
class CustomUserCreationForm(UserCreationForm):
display_image = forms.ImageField(
widget=AdminImageChooser(), label=_('Autorenbild'))}
edit.html
{% extends "wagtailusers/users/edit.html" %}
{% block extra_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.display_image %}
{% endblock extra_fields %}
{% block extra_js %}
{{ block.super }}
{% include 'wagtailadmin/pages/_editor_js.html' %}
{% endblock extra_js %}
create.html similar
What I've tried so far
The idea to use the AdminImageChooser widget I found here. I had to adjust the forms by adding an forms.ImageField so that the User page displays without error.
Questions
Anyone know why the error occurs and how to fix it?
As stated in the above Google group thread, it seems as adding an image to the user model is 'a bit awkward'. What is a better approach to have an image connected to an user for repetitive usage in a site? A requirement is that the image can be easily changed in Wagtail admin.
Other problem with Wagtail version 2.2
In Settings > User in the admin interface, the window of the AdminImageChooser does not open.
Console shows following JS error:
Uncaught ReferenceError: createImageChooser is not defined
On Django 3.0.7 and wagtail wagtail 2.9, I could solve it like this:
models.py
class User(AbstractUser):
avatar = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
forms.py
It's important to use an ModelChoiceField and not an ImageField, so you are compliant with the AdminImageChooser widget.
from django import forms
from wagtail.images import get_image_model
from wagtail.images.widgets import AdminImageChooser
from wagtail.users.forms import UserCreationForm, UserEditForm
class CustomUserEditForm(UserEditForm):
avatar = forms.ModelChoiceField(
queryset=get_image_model().objects.all(), widget=AdminImageChooser(),
)
class CustomUserCreationForm(UserCreationForm):
avatar = forms.ModelChoiceField(
queryset=get_image_model().objects.all(), widget=AdminImageChooser(),
)
Templates
No need to load any Javascript manually. The widget do it for you.
Any-templates-dir/wagtailusers/users/create.html
{% extends "wagtailusers/users/create.html" %}
{% block extra_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.avatar %}
{% endblock extra_fields %}
Any-templates-dir/wagtailusers/users/edit.html
{% extends "wagtailusers/users/edit.html" %}
{% block extra_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.avatar %}
{% endblock extra_fields %}
Was using the last proposed solution in the same Google groups thread, also got the ReferenceError: createImageChooser is not defined js problem after updating from Wagtail 2.1 to 2.2
Here is how my research went:
Looks like this commit removed direct media js inclusion from _editor_js.html.
Okay, so the solution is to replicate the old behavour, and access the Media subclasses of widgets
First I tried adding the same removed lines to my own edit.html in {% block extra_js %}. Did not work.
Looks like some views return edit_handler, like here. User view does not.
What user view does provide, however, is form variable, in both create and edit views. Let's use it.
And the final solution for me was changing extra_js block in edit.html like so:
{% block extra_js %}
{{ block.super }}
{% include 'wagtailadmin/pages/_editor_js.html' %}
{{ form.media.js }}
{% endblock extra_js %}
models.py
class User(AbstractUser):
first_name = models.CharField(max_length=40, blank=False)
image = models.ImageField(blank=False, null=False, upload_to='image/', default='img/user.jpg')
def __str__(self):
return self.username
'''here you can add a model and their requirements too u can set path to remember one thing that image folder will create in media folder..so don't forget to add that folder there. like if you find it helpful'''
forms.py
class UserRegistrationForm(forms.ModelForm):
confirm_password2 = forms.CharField(widget=forms.PasswordInput,required=False)
class Meta:
model = User
fields = ['first_name','username','password','confirm_password2','image']
def clean(self):
cleaned_data = super(UserRegistrationForm, self).clean()
password = cleaned_data.get("password")
confirm_password2 = cleaned_data.get("confirm_password2")
if password != confirm_password2:
self.add_error('confirm_password2', "Password does not match")
return cleaned_data
'''def clean for password validation and i directly added fields which field i want in it'''
views.py
def Register_view(request):
form = UserRegistrationForm()
if request.method == 'POST':
form = UserRegistrationForm(request.POST, request.FILES)
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get("password")
user.set_password(password)
user.save()
return redirect('login')
return render(request, 'register.html', {'form': form})
''' use request.files to add imagein your form'''
register.html
<form action="{% url 'register' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="body bg-gray">
<div class="form-group">
{{ form.as_p }}
</div>
</div>
<div class="footer">
<button type="submit" class="btn bg-olive btn-block">Sign me up</button>
I already have Account
</div>
</form>
''' user multipart to add image in it'''
For me the solution was to make sure you initialise the image field widget on the create and edit form classes with the AdminImageChooser
from wagtail.users.forms import UserEditForm
from wagtail.images.widgets import AdminImageChooser
class CustomUserEditForm(UserEditForm):
...
mugshot = AdminImageChooser()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['mugshot'].widget = AdminImageChooser()
You need to do this when you subclass the UserCreationForm too.
Django 3.2.6, Wagtail 2.14
I've seen similar types of problems on here but I still haven't been able to work out my problem. When I save PhotographerProfileForm in my view, the form is rendered correctly but after clicking update/submit nothing is actually saved.
No errors are shown either.
What I have now are the fields are prepopulated and I would like the ability to save over these in the database, but nothing happens and at the moment you can only update it from the admin panel.
models.py
from __future__ import unicode_literals
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
class PhotographerProfile(models.Model):
user = models.OneToOneField(User)
location = models.CharField(max_length=200)
bio = models.TextField(max_length=500)
def __str__(self):
return self.user.username
User.profile = property(lambda u: PhotographerProfile.objects.get_or_create(user=u)[0])
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def create_profile(sender,instance,created,**kwargs):
if created:
profile, new = PhotographerProfile.objects.get_or_create(user=instance)
urls.py
urlpatterns = [
url(r'^profile/$', 'photoprofile.views.photographer_profile', name = 'photographer_profile'),
url(r'^profile/portfolio/$', 'photoprofile.views.photographer_portfolio', name='photographer_portfolio'),
]
views.py
#login_required
def photographer_profile(request):
photographerProfile = PhotographerProfile.objects.get(user=request.user)
form = PhotographerProfileForm(initial={'bio':photographerProfile.bio, 'location':photographerProfile.location})#This means you can prepoulate it
return render_to_response('photographerprofile.html',{'form':form}, RequestContext(request))
if request.method == 'POST':
form = PhotographerProfileForm(request.POST, instance = request.user.profile,)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/profile')
else:
user = request.user
profile = user.profile
form = PhotographerProfileForm()
return render(request, 'photographerprofile.html', {'form':form})
def photographer_portfolio(request):
photographerProfile = PhotographerProfile.objects.get(user=request.user)
return render_to_response('photographerportfolio.html', {'photographerProfile':photographerProfile}, RequestContext(request))
forms.py
class PhotographerProfileForm(forms.ModelForm):
class Meta:
model = PhotographerProfile
exclude = ('user',)
photographerprofile.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h2> Profile</h2>
{% for field in form %}
{{ field.error}}
{% endfor %}
<form action='/accounts/profile/' method='post'>
{% csrf_token %}
{{form|crispy}}
<input type='submit' value='Update'/>
<p>Click <a href='/accounts/profile/portfolio/'>here</a> to view portfolio. </p>
</form>
{% endblock %}
You return in the third line of your view, before the form has been processed. Remove that line.