I am working on a Role Based Access Control system on django.where at the signup/register people will be designated to a 'department' and will be assigned a 'role' Hence I created a custom user model
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
DEPARTMENT_CHOICES = (
('Production', 'Production'),
('Marketing', 'Marketing'),
('IT', 'IT'),
('HR', 'HR'),
('Accounts', 'Accounts'),
)
ROLE_CHOICES = (
('Manager', 'Manager'),
('Team Lead', 'Team Lead'),
('Member', 'Member'),
)
user = models.OneToOneField(
User,)
department = models.CharField(
max_length=50, choices=DEPARTMENT_CHOICES, null=True)
role = models.CharField(max_length=50, choices=ROLE_CHOICES, null=True)
def __unicode__(self):
return unicode(self.user.first_name + ' ' + self.user.last_name)
def __str__(self):
return self.user.first_name + ' ' + self.user.last_name
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = Profile.objects.create(user=kwargs['instance'])
pass
post_save.connect(create_profile, sender=User)
Then i created a form like
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Profile
class SignUpForm(UserCreationForm):
DEPARTMENT_CHOICES = (
('Production', 'Production'),
('Marketing', 'Marketing'),
('IT', 'IT'),
('HR', 'HR'),
('Accounts', 'Accounts'),
)
ROLE_CHOICES = (
('Manager', 'Manager'),
('Team Lead', 'Team Lead'),
('Member', 'Member'),
)
first_name = forms.CharField(
max_length=30, required=True, help_text='Optional.')
last_name = forms.CharField(
max_length=30, required=True, help_text='Optional.')
email = forms.EmailField(
max_length=254, required=False)
department = forms.ChoiceField(choices=DEPARTMENT_CHOICES, )
role = forms.ChoiceField(choices=ROLE_CHOICES, )
class Meta:
model = User
fields = ('first_name', 'last_name', 'username',
'email', 'password1', 'password2', 'department', 'role')
The my views
from django.shortcuts import render, redirect, render_to_response
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate
from .forms import SignUpForm
from .models import Profile
from django.shortcuts import get_object_or_404
from django.http import Http404
from django.contrib.auth.models import User
from django.template import RequestContext
def register(request):
if request.user.is_authenticated:
if request.user.is_superuser or request.user.role == 'Manager':
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
userprofile = Profile.objects.update(
user=user, department=form.cleaned_data['department'])
userprofile = Profile.objects.update(
user=user, role=form.cleaned_data['role'])
else:
form = SignUpForm()
c = {
'form': form,
}
return render(request, 'registration/register.html', c)
else:
raise Http404
else:
raise Http404
my register.html
{% extends 'layouts/base.html' %} {% load widget_tweaks %}{% block additionalbottom %}
<script>
var allParas = document.getElementsByTagName('div');
//filter by class name if desired...
for (var i = 0; i < allParas.length; i++) {
if (allParas[i].getElementsByTagName('*').length == 0) {
allParas[i].style.display = 'none';
}
}
</script>
{% endblock %} {% block content %}
<div class="login-page">
<div class="form">
<h2>User Registration</h2>
<form class="login-form" method="post">
{% csrf_token %}
<div class="row">
{% endblock %} {% for field in form %}
<div class="col-md-6">
{% if field.name == "first_name" or field.name == "last_name" %} {% render_field field class="form-control" placeholder=field.label.capitalize %} {% endif %}
</div>
<div class="col-md-6">
{% if field.name == "username" or field.name == "email" %} {% render_field field class="form-control" placeholder=field.label.capitalize %} {% endif %}
</div>
<div class="col-md-6 form-group">
{% if field.name == "department" or field.name == "role" %} {% render_field field class="form-control" placeholder=field.label.capitalize %} {% endif %}
</div>
<div class="col-md-12">
{% if field.name == "password1" %} {% render_field field class="form-control" placeholder=field.label.capitalize %} {% endif %}
</div>
<div class="col-md-12">
{% if field.name == "password2" %} {% render_field field class="form-control" placeholder=field.label.capitalize %} {% endif %}
</div>
{% endfor %}
</div>
<div class="form-group">
<button type="submit">Register</button>
</div>
</form>
{% if form.errors %} {% for field in form %} {% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %} {% endfor %} {% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %} {% endif %}
</div>
now when ever i try to submit my form it says
IntegrityError at /register/
column user_id is not unique
i tried so many solutions from google and SO nothing seems to solve the problem can anyone tell me how to fix it or why it cannot be done if it cannot be done what is the work around
This is your problem.
Profile.objects.update(user=user, department=form.cleaned_data['department'])
This will attempt to update all profiles with the same data. If you have more than one Profile, that's not allowed, since user is a one-to-one relation.
I guess what you want to do is to create a new profile object instead. Try something like this:
Profile.objects.create(
user=user,
department=form.cleaned_data['department'],
role=form.cleaned_data['role'],
)
If you use a signal to create the Profile when you save a new User, you can use update_or_create instead.
Profile.objects.update_or_create(
user=user,
defaults={
"department": form.cleaned_data['department'],
"role": form.cleaned_data['role'],
}
)
This post helped me so much. For me, my issue was I used:
current_user = request.user
when it should have been:
current_user = form.save()
Related
I created a system with Django. I need user update section for this project. At the beginning of the project the user change form was working but now it doesnt work. I have a hiden field in my form and I think that's the problem but I'm not sure. Can you help me?
view.py
def update_user(request, id):
user = get_object_or_404(UserProfile, id=id)
form = SignUpForm(request.POST or None, request.FILES or None, instance=user)
if form.is_valid():
form.save()
return redirect('/')
context = {
'form': form,
}
return render(request, "update_user.html", context)
models.py
class UserProfile(AbstractUser):
ranks = (
('Analyst', 'Analyst'),
...
('Chief Financial Officer', 'Chief Financial Officer'),
)
comp_name = models.CharField(max_length=200, default='', blank=True, null=True)
user_id = models.UUIDField(default=uuid.uuid4(), editable=False, unique=True)
....
rank = models.CharField(max_length=200, choices=ranks)
image = models.ImageField(upload_to='profile_image', blank=True, null= True, default='profile.png')
def __str__(self):
return self.username
def get_unique_slug(self):
slug = slugify(self.slug.replace('ı', 'i'))
unique_slug = slug
counter = 1
while UserProfile.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, counter)
counter += 1
return unique_slug
forms.py
class SignUpChangeForm(UserChangeForm):
class Meta:
model = UserProfile
fields = (
'username', 'first_name', 'last_name', 'email', 'rank', 'comp_name', 'image'
)
def clean_password(self):
return self.clean_password
update_user.html
<form method="post">
{{ form|crispy }}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
{% csrf_token %}
<button type="submit" class="btn btn-success">Update</button>
</form>
Error in the form
Hi I have created a address model and link that model to the forms and created the view. but that form does save any data but that data does not show to me. Although it show me that data in the terminal .
this is my address model:
from django.db import models
from billing.models import BillingProfile
# Create your models here.
ADDRESS_TYPES = (
('billing' , 'Billing'),
('shipping' , 'Shipping'),
)
class Address(models.Model):
billing_profile = models.ForeignKey(BillingProfile , on_delete=models.CASCADE)
addresss_type = models.CharField(max_length=120 , choices=ADDRESS_TYPES)
address_line_1 = models.CharField(max_length=120)
address_line_2 = models.CharField(max_length=120 , null=True , blank= True)
city = models.CharField(max_length=120)
country = models.CharField(max_length=120 ,default='Pakistan')
postal_code = models.CharField(max_length=120)
def __str__(self):
return str(self.billing_profile)
since I connect address model with billingprofile so the billing model is:
class BillingProfile(models.Model):
user = models.OneToOneField(User ,null=True , blank=True , on_delete=models.CASCADE)
email = models.EmailField()
active =models.BooleanField(default=True)
update = models.DateTimeField(auto_now=True)
time_stamp = models.DateTimeField(auto_now_add=True)
objects = BillingProfileManager()
def __str__(self):
return self.email
and I call my address model into form
forms.py/address
from django import forms
from .models import Address
class AddressForm(forms.ModelForm):
class Meta:
model = Address
fields = ['address_line_1','address_line_2','city','country','postal_code']
and my address/views.py is:
from django.shortcuts import render , redirect
from django.utils.http import is_safe_url
# Create your views here.
from billing.models import BillingProfile
from .forms import AddressForm
def checkout_address_create_view(request):
form = AddressForm(request.POST or None)
context = {
'form':form
}
next_ = request.GET.get('next')
next_post = request.POST.get('next')
redirect_path = next_ or next_post or None
if form.is_valid():
print(request.POST)
instance = form.save(commit=False)
billing_profile , billing_profile_created = BillingProfile.objects.new_or_get(request)
if billing_profile is not None:
instance.billing_profile = billing_profile
instance.address_type = request.POST.get('address_type','shipping')
instance.save()
else:
print("Error Here")
return redirect("cart:checkout")
if is_safe_url(redirect_path , request.get_host()):
return redirect(redirect_path)
else:
return redirect("cart:checkout")
return redirect("cart:checkout")
and my address/form.html is:
now my form.html is:
<form method="POST" action="{% if action_url%}{{ action_url }} {% else %}{% url 'login' %}{% endif %}">
{% csrf_token %}
{% if next_url %}
<input type="hidden" name="next" value="{{ next_url }}"/>
{% endif %}
{% if address_type %}
<input type="hidden" name="address_type" value="{{ address_type }}"/>
{% endif %}
{{form.as_p}}
<button type="submit" class="btn btn-secondary">Submit</button>
</form>
and this form is shown on cart home so the cart view is:
def checkout_home(request):
cart_obj , cart_created = Cart.objects.new_or_get(request)
order_obj = None
if cart_created or cart_obj.products.count() ==0:
return redirect("cart:home")
login_form = LoginForm()
guest_form = GuestForm()
address_form =AddressForm()
billing_address_form = AddressForm()
billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
if billing_profile is not None:
order_obj , order_obj_created = Order.objects.new_or_get(billing_profile , cart_obj)
context= {
"object" : order_obj,
"billing_profile" : billing_profile,
"login_form" : login_form,
"guest_form" :guest_form,
"address_form" :address_form,
"billing_address_form" : billing_address_form,
}
return render(request , "carts/checkout.html" , context)
and my checkout html is:
{% extends 'base.html' %}
{% block content %}
{{object.order_id}} -- {{object.cart}}
{% if not billing_profile %}
<div class="row text-center">
<div class="col-12 col-md-6">
<p class="lead">Login</p>
{% include 'accounts/snippets/form.html' with form=login_form next_url=request.build_absolute_uri %}
</div>
<div class="col-12 col-md-6">
<p class="lead">Continue as guest</p>
{% url "guest_register" as guest_register_url %}
{% include 'accounts/snippets/form.html' with form=guest_form next_url=request.build_absolute_uri action_url=guest_register_url %}
</div>
</div>
{% else %}
{% if not object.shipping_address %}
<div class="row">
<div class="col-md-6 mx-auto col-10">
<p class="lead">Shipping Address</p>
{% url "checkout_address_create" as checkout_address_create %}
{% include 'addresses/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='shipping' %}
</div>
</div>
{% elif not object.billing_address%}
<div class="row">
<div class="col-md-6 mx-auto col-10">
<p class="lead">Billing Address</p>
{% url "checkout_address_create" as checkout_address_create %}
{% include 'addresses/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='billing' %}
</div>
</div>
{% else %}
<h1>Finalize Checkout</h1>
<p>Cart_total:{{object.cart.total}}</p>
<p>Shipping Total:{{object.shipping_total}}</p>
<p>Order Total:{{object.total}}</p>
<button>Checkout</button>
{% endif %}
{% endif %}
{% endblock %}
ValueError at /students/addgrregister/
i am trying to add students in gr_register but its giving an error due to this error the code is not working i also upload the template (addgrregister.html) kndly tell me where is the issue in these pages
models.py
class gr_register(models.Model):
Gender_Choices = (
('M', 'Male'),
('FM', 'Female'),
)
Status_Choices = (
('P', 'Present'),
('FM', 'Left'),
)
gr_no = models.IntegerField(primary_key=True)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
date_birth = models.DateField(null=True)
classes_A = models.ForeignKey(Classes, on_delete=models.CASCADE, related_name="classes_A", default=1, verbose_name="Class of Admission")
sections_A = models.ForeignKey(Sections, on_delete=models.CASCADE, related_name="sections_A", default=1, verbose_name="Section of Admission")
gender = models.CharField(max_length=10, choices=Gender_Choices)
classes_C = models.ForeignKey(Classes, on_delete=models.CASCADE, related_name="classes_C", verbose_name="Current Class")
sections_C = models.ForeignKey(Sections, on_delete=models.CASCADE, related_name="sections_C", verbose_name="Current Section")
address = models.CharField(max_length=100, null=True, verbose_name="Home Address")
area_code = models.ForeignKey(Area, on_delete=models.CASCADE, verbose_name="Area")
status = models.CharField(max_length=10, choices=Status_Choices, default='P')
class Meta:
ordering = ('gr_no',)
def __str__(self):
return self.first_name
views.py
from django.shortcuts import get_object_or_404, render, redirect
def addgrregister(request):
if request.method == 'POST':
form = gr_registerForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = gr_registerForm()
return render(request, 'students/addgrregister.html', {'form': form})
forms.py
from django import forms
from django.forms import ModelChoiceField, ModelForm
from .models import *
class gr_registerForm(ModelForm):
classes_A = forms.ModelChoiceField(queryset=Classes.objects.all())
sections_A = forms.ModelChoiceField(queryset=Sections.objects.all())
classes_C = forms.ModelChoiceField(queryset=Classes.objects.all())
sections_C = forms.ModelChoiceField(queryset=Sections.objects.all())
area_code = forms.ModelChoiceField(queryset=Area.objects.all())
class Meta:
model = gr_register
fields = '__all__'
def init(self, *args, **kwargs):
forms.ModelForm.init(self, *args, **kwargs)
addgrregister.html
{% extends 'authenticate/base.html' %}
{% block content %}
<div class="container">
<h4 class="text-center">ADD GR_REGISTER</h4>
<hr/>
<form method="POST" action="{% url 'addgrregister' %}" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
<label for="id_{{ field.name }}" class="col-2 col-form-label">{{ field.label }}</label>
<div class="col-10">
{{ field }}
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary" name="button">Add GR_REGISTER</button>
</form>
<br/><br/>
</div>
{% endblock %}
There is nothing returned when form is not valid. I think you try like this:
def addgrregister(request):
form = gr_registerForm(request.POST or None) # it initates a form. If the request type is POST, then there will be a dict available with posted data in request.POST. If request is not POST, then the form will initiate with empty data.
if request.method == 'POST':
if form.is_valid(): # Form valid checks if the submitted form is valid or not. If not, it will store errors in the form. When that form is passed to template, it will show errors in html
form.save() # It will store data in DB
return redirect('home')
# when for is invalid, it will show the error in the form
return render(request, 'students/addgrregister.html', {'form': form})
Update
Show form errors in template:
{% for field in form %}
<div class="form-group row">
<label for="id_{{ field.name }}" class="col-2 col-form-label">{{ field.label }}</label>
<div class="col-10">
{{ field }}
{{ field.errors }} // <-- Updated here
</div>
</div>
{% endfor %}
I have models.py and forms.py, views.py and as bellow . I want only alpha numeric inputs . after submitting the form, i am getting the error :'ErrorDict' object has no attribute 'status_code'
Kindly suggest .
from django.core.validators import RegexValidator
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed.')
class News_Post(models.Model):
Country=models.CharField(max_length=20, validators=[alphanumeric])
State=models.CharField(max_length=20, validators=[alphanumeric])
District=models.CharField(max_length=20, validators=[alphanumeric])
Area=models.CharField(max_length=20, validators=[alphanumeric])
Photo_link=models.CharField(max_length=50,blank=True)
News_Title=models.CharField(max_length=200, validators=[alphanumeric])
News=models.TextField(validators=[alphanumeric])
created_date=models.DateTimeField(auto_now_add=True,)
author = models.CharField(max_length=20)
def __str__(self):
return self.News_Title
forms.py:
from django import forms
from django.forms import ModelForm
class NewsForm(forms.ModelForm):
Country=forms.CharField(max_length=20, required=False, help_text='Optional.')
State=forms.CharField(max_length=20, required=False, help_text='Optional.')
District=forms.CharField(max_length=20, required=False, help_text='Optional.')
Area=forms.CharField(max_length=20, required=False, help_text='Optional.')
Photo_link=forms.CharField(max_length=50, required=False, help_text='Optional.')
News_Title=forms.CharField(max_length=200, required=True, help_text='Required')
News=forms.CharField(widget=forms.Textarea)
class Meta:
model = News_Post
fields = ('Country','State','District','Area','Photo_link','News_Title', 'News', )
exclude = ["author"]
Views.py:
.
def new_submit(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
c=form.save(commit=False)
c.author = request.user
c.save()
return redirect(my_submitted_news )
else:
return form.errors
else:
form = NewsForm()
return render(request,'new_submit.html', {'form': form})
new_submit.html:
{% block content %}
{% if form.errors %}
<p style="color: red"> Please try again.</p>
{% endif %}
<form method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit">Submit News</button>
{% endblock %}
Edit your view,
def new_submit(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid():
c=form.save(commit=False)
c.author = request.user
c.save()
return redirect('your_url_name' )
else:
return render(request, 'template_name', dict(form, form))
else:
form = NewsForm()
return render(request,'new_submit.html', {'form': form})
When the form is not valid, your else statement returns form.errors directly. That is not a valid thing to return from a view; views always need to return an HTTP response.
You should remove that first else statement, and let execution fall through to the final line so that your template is rendered with the invalid form. You should also modify the template so that it actually outputs the contents of form.errors.
I have been reading the django documentation, googling for days where none have the same problem as me. It seems that method "member_edit" in "Views.py" does not return any data and therefor can not show me the form.
Hopefully, some of you can spot where I went wrong. Appreciate all the help I can get!
Models.py
class Member(models.Model):
member_no = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50, null=True, blank=True)
email = models.CharField(max_length=50, null=True, blank=True)
reg_date = models.DateTimeField(null=True, blank=True)
class Meta:
db_table = 'Member'
Forms.py
class RegForm(forms.ModelForm):
first_name = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'}),
max_length=30,
required=True)
last_name = forms.CharField(
widget=forms.TextInput(attrs={'class': 'form-control'}),
max_length=30,
required=True)
email = forms.CharField(
widget=forms.EmailInput(attrs={'class': 'form-control'}),
required=True,
max_length=75)
reg_date = forms.DateField(widget=DateWidget(usel10n=True,bootstrap_version=3))
class Meta:
model = Member
exclude = ['last_login', 'date_joined']
fields = ['first_name', 'last_name', 'email', 'reg_date', ]
Views.py
def member_edit(request, member_no):
member = Member.objects.get(member_no=member_no)
if request.method == 'POST':
form = RegForm(request.POST or None, instance=member)
if form.is_valid():
member.first_name = form.request.POST['first_name']
member.last_name = form.request.POST['last_name']
member.email = form.request.POST['email']
member.reg_date = form.request.POST['reg_date']
member.save()
return redirect('member_overview')
return render(request, 'member/member_signup.html')
urls.py
urlpatterns = [
url(r'^member_edit/(?P<member_no>\d+)$', views.member_edit, name='member_edit')
]
member_edit.html
{% block body %}
<h1 class="logo">Members</h1>
<div class="signup">
<h2>{% trans 'Update member' %}</h2>
<form action="{% url 'member_edit' member.member_no %}" method="post" role="form">
{% csrf_token %}
{% for field in form.visible_fields %}
<div class="form-group{% if field.errors %} has-error{% endif %}">
<label for="{{ field.label }}">{{ field.label }}</label>
<div class="col-sm-10">
{{ field }}
{% if field.help_text %}
<span class="help-block">{{ field.help_text }}</span>
{% endif %}
{% for error in field.errors %}
<label class="control-label">{{ error }}</label>
{% endfor %}
</div>
</div>
{% endfor %}
<center>
<button type="submit" class="btn btn-primary">{% trans 'Update member' %}</button>
</center>
</form>
</div>
{% endblock body %}
You're not passing the form in the context (and the template name appears to be incorrect?):
def member_edit(request, member_no):
member = Member.objects.get(member_no=member_no)
if request.method == 'POST':
form = RegForm(request.POST or None, instance=member)
if form.is_valid():
# This isn't necessary - just save the form
#member.first_name = form.request.POST['first_name']
#member.last_name = form.request.POST['last_name']
#member.email = form.request.POST['email']
#member.reg_date = form.request.POST['reg_date']
#member.save()
form.save()
return redirect('member_overview')
# Instantiate the form
form = RegForm(instance=member)
# Add a dictionary for the context
return render(request, 'member/member_edit.html', {'form': form, 'member': member)
You could make this cleaner (and easier) though with a generic class based view:
from django.views import generic
from django.urls import reverse_lazy
class UpdateMember(generic.UpdateView):
model = Member
form_class = RegForm
pk_url_kwarg = 'member_no'
template_name = 'member/member_edit.html'
success_url = reverse_lazy('member_overview')
Think I got all the attributes you need there - you can check out CCBV it's a great resource for the class based views.
Take a look at the documentation on views and templates