This is my models:
class User(AbstractUser):
"""Default user for awesomeinventory."""
is_organisor = models.BooleanField(default=True)
is_agent = models.BooleanField(default=False)
is_associatetoCompany = models.BooleanField(default=False)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Agent(models.Model):
FUNCTIONS = Choices(
(1, 'Procurement', _('Procurement')),
(2, 'Request_User', _('Request')),
(3, 'Receptionist', _('Receptionist')),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
organisation = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
role = models.PositiveSmallIntegerField(
choices=FUNCTIONS,
default=FUNCTIONS.Request_User,
)
def __str__(self):
return self.user.email
Agent form is:
FUNCTIONS = Choices(
(1, 'Procurement', _('Procurement')),
(2, 'Request_User', _('Request')),
(3, 'Receptionist', _('Receptionist')),
)
class AgentModelForm(forms.ModelForm):
role = forms.ChoiceField(choices=FUNCTIONS, widget=forms.Select, label='Role')
class Meta:
model = User
fields = (
'email',
'username',
'first_name',
'last_name',
'role',
)
my views.py:
class AgentUpdateView(OrganisorAndLoginRequiredMixin, UpdateView):
template_name = "agents/agent_update.html"
form_class = AgentModelForm
def get_success_url(self):
return reverse("agents:agent_list")
def get_queryset(self):
return Agent.objects.all()
I'm working on Agent and I've no issue to create an agent, view details of an agent. I'm using crispy form and generic views.
My update view template is:
{% extends "base.html" %}
{% load tailwind_filters %}
{% block content %}
<form form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="w-full text-white bg-blue-500 hover:bg-blue-600 px-3 py-2 rounded-md">Submit</button>
</form>
{% endblock content %}
In this form all fields stay empty except role. When I look at what is loaded in template, I've Agent instance and User is encapsulated is Agent.
I try to add this in my template :
<span class="ml-auto text-gray-900">{{ agent.user.first_name }} {{ agent.user.last_name }}</span>
with the span I can see values of agent.user.
It seems that {{ form|crispy }} is unable to dive in Agent to find User instance linked to this agent.
I changed my way to code and used a def instead:
def AgentUpdateView(request, pk):
obj = Agent.objects.filter(pk=pk).first()
if obj is None:
return render(request, "404.html", {
"Instance": pk
})
else:
form = AgentModelForm(instance=obj.user)
# manage save
if request.method == "POST":
form = AgentModelForm(request.POST, instance=obj.user)
if form.is_valid():
form.save()
# messages.success(request, 'Agent saved') # message for inform user of success - See messages in html file
return HttpResponseRedirect(reverse("agents:agent_list"))
return render(request, 'agents/agent_update.html', { "agent":obj,
"form": form})
Related
I recently started learning django and was making a CRM.
models.py:
class Complaint(models.Model):
SOURCE_CHOICES=(
('email','E-mail'),
('call','Call'),
('ticket','Ticket')
)
store_name=models.CharField(max_length=20)
store_contact_no=models.IntegerField(max_length=10)
store_id=models.CharField(max_length=7)
source=models.CharField(choices=SOURCE_CHOICES, max_length=10)
agent=models.ForeignKey("Agent", null = True, blank = True, on_delete=models.SET_NULL)
category=models.ForeignKey("Category", related_name="complaints", null = True, blank = True, on_delete=models.SET_NULL)
description = models.TextField()
customer = models.ForeignKey("Customer", null = True, blank = True, on_delete=models.SET_NULL)
def __str__(self):
return f"{self.store_name} {self.store_id}"
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return self.user.username
forms.py
class CustomerComplaintForm(forms.ModelForm):
class Meta:
model = Complaint
fields = (
'store_name',
'store_id',
'store_contact_no',
'description',
)
views.py
class
CustomerComplaintCreateView(OwnerCustomerAndLoginRequiredMixin,
generic.CreateView):
template_name = "customercomplaint_create.html"
form_class = CustomerComplaintForm
def get_success_url(self):
return "/complaints"
def form_valid(self, form):
complaint = form.save(commit=False)
complaint.Customer = self.request.user.username
complaint.source = 'ticket'
complaint.save()
return super(CustomerComplaintCreateView,
self).form_valid(form)
html template:
{% extends "base.html" %}
{% load tailwind_filters %}
{% block content %}
<div class="max-w-lg mx-auto">
<a class="hover:text-blue-500" href="/complaints">Go back to complaints </a>
<div class="py-5 border-t border-gray-200">
<h1 class="text-4xl text-gray-800"> Create a new complaint </h1>
</div>
<form method='post' class="mt-5">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="w-full bg-blue-500 text-white hover:bg-blue-600 px-
3 py-2 rounded-md">Create</button>
</form>
</div>
{% endblock content %}
mixins.py
class OwnerCustomerAndLoginRequiredMixin(AccessMixin):
"""Verify that the current user is authenticated and is an owner or customer"""
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated or not request.user.is_owner and not request.user.is_customer:
return redirect("/complaints")
return super().dispatch(request, *args, **kwargs)
The problem here is that, the source field gets filled in the database with Ticket as intended. But the 'Customer' field is not populated with the username. 'Self.request.user.username' is not the problem here as the username is being printed correctly in the console.
The issue is complaint.Customer = self.request.user.username, you're trying to assign a username to a supposedly Customer object. Here's an approach you could take to solve the issue though.
Within the views.py file, the view class.
You could get the customer object and then assign it to the customer field on the complaint object.
from django.shortcuts import get_object_or_404
def form_valid(self, form):
complaint = form.save(commit=False)
customer = get_object_or_404(Customer, user=self.request.user) # recommended
# or
# customer = get_object_or_404(Customer, user__username__iexact=self.request.user.username)
if customer:
# Here on your model you have a lowercase `c` for the customer field, not 'C`
complaint.customer = customer # -> This will assign the customer object, "FK".
complaint.source = 'ticket'
complaint.save()
return super(CustomerComplaintCreateView, self).form_valid(form)
That should work.
this must be the User not the user name
Because Cutomer is User object not only the Uesrname
def form_valid(self, form):
complaint = form.save(commit=False)
complaint.Customer = self.request.user
complaint.source = 'ticket'
complaint.save()
I'm having a little problem with the .save() method in Django. For 1 form it works, for the other it doesn't. And I can't find the problem.
views.py
#login_required
def stock_add(request, portfolio_id):
if request.method == 'POST':
print('request.method is ok')
form = StockForm(request.POST)
print('form is ok')
if form.is_valid():
print('form is valid')
stock = form.save(commit=False)
stock.created_by = request.user
stock.portfolio_id = portfolio_id
stock.save()
return redirect('portfolio-overview')
else:
print("nope")
else:
print('else form statement')
form = StockForm()
context = {
'form':form
}
return render(request, 'portfolios/stock-add.html', context)
forms.py
class StockForm(ModelForm):
class Meta:
model = Stock
fields = ['quote', 'amount']
html
{% extends 'core/base.html' %}
{% block content %}
<div class="container">
<h1 class="title">Add Stock</h1>
<form method="POST" action=".">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="button is-primary">Submit</button>
</form>
</div>
{% endblock %}
models
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Portfolio(models.Model):
title = models.CharField(max_length=56)
description = models.TextField(blank=True, null=True, max_length=112)
created_by = models.ForeignKey(User, related_name='portfolios', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Portfolio'
def __str__(self):
return self.title
class Stock(models.Model):
Portfolio = models.ForeignKey(Portfolio, related_name='stocks', on_delete=models.CASCADE)
quote = models.CharField(max_length=10)
amount = models.IntegerField()
created_by = models.ForeignKey(User, related_name='stocks', on_delete=models.CASCADE)
created_at = models.DateField(auto_now_add=True)
def __str__(self):
return self.quote
If you look at the views.py file, when I submit the form, it won't even do print('request.method is ok')
I can add the stock via the admin page.
So I have no clew where to look anymore...
Cheers
When you post a form and need a special url (like your' with an attribute), i like to set action="{% url myview.views.stock_add portfolio_id %}"
action="." will save to the same page without taking care of extra parameters (if needed)
Just pass portfolio_id in the context and that will work
I found the answer, an InteregerField (from models.py) needs a default value.
Either default=None (or another value).
Cheers
I'm trying to create a pastebin clone in Django. I've created a paste app, and a Paste class in my models.py
class Paste(models.Model):
SYNTAX_CHOICES = {
(0, "Plain"),
(1, "Python"),
(2, "HTML"),
(3, "SQL"),
(4, "Javascript"),
(5, "CSS"),
}
content = models.TextField()
title = models.CharField(blank=True, max_length=30)
syntax = models.IntegerField(choices=SYNTAX_CHOICES, default=0)
poster = models.CharField(blank=True, max_length=30)
timestamp = models.DateTimeField(default=datetime.datetime.now, blank=True)
class Meta:
ordering = ('-timestamp',)
def __unicode__(self):
return "%s (%s)" % (self.title or "#%s" % self.id,
self.get_syntax_display())
#permalink
def get_absolute_url(self):
return ('django.views.generic.list_detail.object_detail',
None, {'object_id': self.id})
class PasteAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'title', 'poster', 'syntax', 'timestamp')
list_filter = ('timestamp', 'syntax')
admin.site.register(Paste, PasteAdmin)
In one of my templates, I have a form that requires the user enter the required details(name of paste, syntax, paste itself).
{% extends "base.html" %}
{% block content %}
<h1>Your user is</h1>
{{ request.user }}
{{ request.user.is.authenticated }}
<form action="" method="POST">
{% csrf_token %}
Title: <textarea rows="1" cols="50" placeholder="Title of paste"></textarea><br>
Syntax: <textarea rows="1" cols="50" placeholder="Enter syntax"></textarea><br>
{{ form.content }}<br>
<textarea rows="4" cols="50" placeholder="Please enter the text you'd wish to paste..."></textarea>
<input type="submit" name="submit" value="Paste" id="submit">
{% endblock content %}
But when the information is entered, the data is not saved when checking the admin. What am I missing to save the entered information to that specific model?
As well, I have a registration form that creates new users, as well as a form that allows you to login/logout.
pastes/views.py
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('/home')
else:
form = UserCreationForm()
return render(request, 'signup.html', {'form': form})
How would I go about linking the paste to the user? Or, allowing for it to remain anonymous?
Sorry for all the (dumb) questions, I'm quite lost in this and I've only been doing Django for 24 hours.
I created a form to update a User's profile, however when I run it, there are no errors, but when I try to open up the page, the header appears but the UpdateBioForm does not appear. Secondly, I was wondering how you would create a large textbox to store someone's biography.
Models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
biography = models.CharField(max_length = 255, default = '')
city = models.CharField(max_length=100, default = '')
website = models.URLField(default='')
image = models.ImageField(upload_to='profile_image', blank=True)
def setdefault(self, default_path='/profile_image/Default.jpg'):
if self.image:
return self.image
return default_path
def __str__(self):
return self.user.username
Forms.Py
class UpdateBioForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = (
'biography',
'city',
'website'
)
def save(self, commit=True):
savedBio = super(UpdateBioForm, self).save(commit=False)
savedBio.biography = self.cleaned_data['biography']
savedBio.city = self.cleaned_data['city']
savedBio.website = self.cleaned_data['website']
if commit:
savedBio.save()
return savedBio
Views.py
def update_bio(request):
if request.method == 'POST':
form = UpdateBioForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('/')
else:
form = UpdateBioForm(instance=request.user)
args = {'form':form}
return render(request, 'accounts/update_bio.html')
urls.py
url(r'^profile/updatebio/$',views.update_bio, name='update_bio'),
update_bio.html
{% extends 'base.html' %}
{% block body %}
<div class="container">
<h1>Update Biography</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
</div>
{% endblock %}
You are not passing any context to your render() method - you define args but don't do anything with that variable. Change it to:
args = {'form':form}
return render(request, 'accounts/update_bio.html', context=args) # <-- You're missing context
When I update the user profile via the view everything is saving to the db except the image. The forms are validating but image isn't being saved. I can log in the admin portal and successfully add an image to an existing instance. I assume my problem lies in my html template but I can't figure out what it is.
**Btw I've read multiple similiar post but none I believe addresses my issue.
form.py
class EditUserForm(forms.ModelForm):
template_name='/something/else'
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name',
)
class EditProfileForm(forms.ModelForm):
template_name='/something/else'
class Meta:
model = UserProfile
fields = (
'description',
'city',
'website',
'phone',
'image',
)
views.py
#transaction.atomic
def edit_profile(request):
if request.method == 'POST':
form = EditUserForm(request.POST, instance=request.user)
form2 = EditProfileForm(request.POST, instance=request.user.userprofile)
if form.is_valid() and form2.is_valid():
form.save()
form2.save()
return redirect(reverse('accounts:view_profile'))
else:
form = EditUserForm(instance=request.user)
form2 = EditProfileForm(instance=request.user.userprofile)
args = {'form': form, 'form2':form2}
return render(request, 'accounts/edit_profile.html', args)
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
description = models.CharField(max_length=100, default='')
city = models.CharField(max_length=100, default='')
website = models.URLField(default='')
phone = models.IntegerField(default=0)
image = models.ImageField(upload_to='profile_image', blank=True)
def __str__(self):
return self.user.username
edit_profile.html
<div class="container">
{% if form.errors %}
<ol>
{% for field in form %}
<H3 class="title">
<p class="error"> {% if field.errors %}<li>{{ field.errors|striptags }}</li>{% endif %}</p>
</H3>
{% endfor %}
</ol>
{% endif %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
{{ form2.as_p }}
<button type="submit">Submit</button>
</form>
<br>
</div>
If you are uploading files, you must instantiate the form with request.POST and request.FILES.
form2 = EditProfileForm(request.POST, request.FILES, instance=request.user.userprofile)
See the docs on file uploads for more info.