How to implement unique together in Django - python

im working on a sales team project where i'm trying to implement a function to upload their daily visit plan. While uploading i want to put a validation that, if visit for one customer is already uploaded then for same another wouldn't be uploaded and would raise a error like" Visit plan for this customer already exists on this date". I have read some where that unique together would help me to validate but im not sure how to use unique together in View. please find the below codes for your reference and help. Thanks in advance
Model:
class BeatPlan(models.Model):
beat_id = models.CharField(unique=True, max_length=15, null=True)
beat_dealer = models.ForeignKey(Dealer, null=True, on_delete=models.SET_NULL)
beat_user = models.ForeignKey('account.CustomUser', null=True, on_delete=models.SET_NULL)
beat_stake_holder = models.ForeignKey(StakeHolder, null=True, on_delete=models.SET_NULL)
beat_date = models.DateField(null=True)
create_date = models.DateField(null=True)
beat_status = models.CharField(choices=(('Not visited', 'Not visited'), ('Visited', 'Visited')),
default='Not visited', max_length=40, null=True)
beat_location = models.CharField(max_length=200, null=True)
beat_type = models.CharField(choices=(('Not planned', 'Not planned'), ('Planned', 'Planned')), max_length=50,
null=True)
beat_reason = models.CharField(max_length=200, null=True)
class Meta:
unique_together = ('beat_date', 'beat_dealer')
def __str__(self):
return str(self.beat_user) + str(self.beat_dealer) + str(self.beat_date)
View:
def upload_beat(request):
global u_beat_dealer, beat_user_id, beat_date
template = "upload_beat.html"
data = BeatPlan.objects.all()
l_beat = BeatPlan.objects.last()
l_beat_id = l_beat.id
print(l_beat_id)
current_month = datetime.datetime.now().strftime('%h')
# prompt is a context variable that can have different values depending on their context
prompt = {
'order': 'Order of the CSV should be name, email, address, phone, profile',
'profiles': data
}
# GET request returns the value of the data with the specified key.
if request.method == "GET":
return render(request, template, prompt)
csv_file = request.FILES['file']
# let's check if it is a csv file
if not csv_file.name.endswith('.csv'):
messages.error(request, 'THIS IS NOT A CSV FILE')
data_set = csv_file.read().decode('UTF-8')
# setup a stream which is when we loop through each line we are able to handle a data in a stream
io_string = io.StringIO(data_set)
next(io_string)
for column in csv.reader(io_string, delimiter=',', quotechar="|"):
u_beat_user_id = column[0]
u_beat_dealer = column[1]
beat_date = column[2]
print(u_beat_user_id)
if StakeHolder.objects.filter(unique_id=u_beat_user_id).exists():
user_id = StakeHolder.objects.get(unique_id=u_beat_user_id)
beat_user_id = user_id.id
if Dealer.objects.filter(dealer_code=u_beat_dealer).exists():
dealer_id = Dealer.objects.get(dealer_code=u_beat_dealer)
u_beat_dealer = dealer_id.id
l_beat_id += 1
u_beat_id = current_month + str(l_beat_id)
newBeatPlan = BeatPlan(beat_id=u_beat_id, beat_dealer_id=u_beat_dealer,
beat_stake_holder_id=beat_user_id,
beat_date=beat_date)
newBeatPlan.save()
messages.success(request, ' Beat added')
else:
messages.error(request, 'Dealer id does not exists')
else:
messages.error(request, "Unique ID doesn't exists")
context = {'beat_user': beat_user_id, 'dealer_code': u_beat_dealer, 'visit_date': beat_date}
return render(request, template, context)
Template:
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h3 style="margin-left: 10px">Upload Beat</h3>
<div class="row" style="margin-left: 5px">
<div class="col-md-6">
<hr>
{{ order }}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<label for="file1"> Upload a file</label>
<input type="file" id="file1" name="file" required><br><br><br><br><br>
<small>Only accepts CSV files</small>
<button class="btn btn-primary if-error-not-found" type="submit"
name="submit">Upload</button>
<a href="{% url 'beatplan' %}">
<div class="btn btn-primary back-button">Back</div>
</a>
</form>
<br>
<br>
</div>

unique_together validates the data that is saved on the database. However, you can still submit forms where those 2 fields are not unique and get an error on your backend. What you need to do is to handle that error manually. Django forms have a method add_error(field, error). However, as I see, you do not use them, so you can just add an error parameter while rendering your template. Manually check if the customer has an input for that date, and add that error without saving anything to your database. Must look like this.
context['error'] = false
if YourModel.objects.filter(fields1=field1, field2=field2).exists():
# your code that does not save anything
context['error'] = true
return render(request, template, context)
And handle the error on your template however you want.
unique_together will make sure that whatever you do, invalid data is not saved, so keep it.

Related

Django Handling Multiple Image Uploads

I have a simple project that has two different models. One that handles a report and one that stores the images for each report connected by a ForeignKey:
class Report(models.Model):
report_location = models.ForeignKey(Locations, on_delete=models.CASCADE)
timesheet = models.ImageField(upload_to='report_images', default='default.png')
text = models.CharField(max_length=999)
report_date = models.DateField(auto_now=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return f"{self.report_location, self.report_date, self.created_by}"
class TimeSheetAndPics(models.Model):
report = models.ForeignKey(Report, on_delete=models.CASCADE)
report_images = models.ImageField(upload_to='report_images', default='default.png')
date = models.DateField(auto_now=True)
def __str__(self):
return f"{self.report} on {self.date}"
My Goal is to have a user fill out the report and then upload multiple pictures, however i cannot figure out how to handle multiple image uploads.
I have two forms for each model:
class ReportCreationForm(ModelForm):
class Meta:
model = Report
fields = [
'report_location',
'text',
]
class TimeSheetAndPicForm(ModelForm):
report_images = forms.FileField(widget=ClearableFileInput(attrs={'multiple': True}))
class Meta:
model = TimeSheetAndPics
fields = [
'report_images',
]
And this is how i try to handle my views:
class NewReport(LoginRequiredMixin, View):
def get(self, request):
context = {
'create_form': ReportCreationForm(),
'image_form': TimeSheetAndPicForm(),
}
return render(request, 'rakan/report_form.html', context)
def post(self, request):
post = request.POST
data = request.FILES or None
create_form = ReportCreationForm(post)
image_form = TimeSheetAndPicForm(post, data)
if create_form.is_valid() and image_form.is_valid():
clean_form = create_form.save(commit=False)
clean_form.created_by = request.user
clean_form.save()
clean_image_form = image_form.save(commit=False)
for images in clean_image_form:
clean_image_form.report = clean_form
clean_image_form.report = images
clean_image_form.save()
return redirect('rakan:rakan_index')
return redirect('rakan:new-report')
I have tried to solve this in different ways but i unfortunately hit a wall. I cant seem to find a solution that actually works. My best try i was able to save only 1 image in the models instead of the 3 test images.
I dont believe it makes a difference but here is also the HTML File that uses the forms:
<div class="content-section">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Report</legend>
{{ create_form }}
<br>
{{ image_form }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">submit</button>
</div>
</form>
</div>
Anyone dealt with this problem would like to help me achieve a solution i would be very thankful. Thank you.

How to Store the Data in Database from dropdown in Djngo

I am working on student management project and I am unable to get the branch for student as it is foreignkey of Course model to Student model and I want to get the selected option into student model in branch row
models.py:
class Course(models.Model):
id=models.AutoField(primary_key=True)
course = models.CharField(max_length=50)
course_code = models.BigIntegerField(null=True)
def __str__(self):
return self.course
class Student(models.Model):
id=models.AutoField(primary_key=True)
user=models.OneToOneField(User,on_delete=models.CASCADE)
branch=models.ForeignKey(Course,on_delete=models.CASCADE,null=True,blank=True)
middle_name=models.CharField(max_length=50,null=True)
roll_no=models.IntegerField()
mobile_no=PhoneNumberField(default='')
parents_mobile_no=PhoneNumberField(default='')
division=models.CharField(max_length=10,null=True)
batch=models.CharField(max_length=10,null=True)
def __str__(self):
return self.user.first_name + " " + self.user.last_name
views.py:
def studentregister(request):
if request.method == 'POST':
first_name = request.POST['first_name']
middle_name = request.POST['middle_name']
last_name = request.POST['last_name']
email = request.POST['email']
branch= request.POST['branch']
division = request.POST['division']
roll_no = request.POST['roll_no']
mobile_no = request.POST['mobile_no']
parents_mobile_no = request.POST['parents_mobile_no']
pass1 = request.POST['password']
pass2 = request.POST['confirmpassword']
if pass1 == pass2 :
if User.objects.filter(email=email).exists():
return HttpResponse('User already exsits')
else:
user = User.objects.create_user(email=email, password=pass1, first_name=first_name, last_name=last_name)
user.save();
studentdetails = Student ( user=user, middle_name=middle_name,roll_no=roll_no,mobile_no=mobile_no,parents_mobile_no=parents_mobile_no, branch=branch,division=division)
studentdetails.save();
return render (request, 'ms/homepage/index.html')
else:
return HttpResponse('password does not match')
else:
return HttpResponse('failed')
def staffstudent(request):
if request.user.is_authenticated and request.user.user_type==3:
courses = Course.objects.all()
return render(request, 'ms/staff/student.html',{'courses':courses})
else:
return render(request,'ms/login/login.html')
html file as student.py:
<form action="studentregister" method="POST" style = "background-color:#011B3C;">
{% csrf_token %}
<div class="form-group" name="branch">
<select >
<option selected disabled="true">Branch</option>
{% for course in courses%}
<option>{{course.course}}</option>
{%endfor%}
</select>
</div>
</form>
The error I am getting is
MultiValueDictKeyError at /staff/studentregister
'branch'
Please help me with this as soon as possible.
You haven't named that <select> (<select name="branch">) so any choice you make in it will not be transmitted to the server, and that's why you get a key error.
In addition, the <option>'s value must be the course's id:
<option value="{{ course.id }}">{{ course.course }}</option>
... so you can look it up in the view:
branch = Course.objects.get(id=request.POST['branch'])
However, please look at Django's built-in forms functionality, especially model forms – you would be done in a fraction of the HTML and Python code you have now, plus you'd actually have correct data validation.
This is not the conventional way to deal with Forms in Django although it can be done. Convention would be:
Creating a form in forms.py like so:
class MyForm(forms.Form):
dropdown_one = forms.ChoiceField(
label="Country",
widget=forms.Select(attrs={"class": "selecter form-control"}),
choices=[],
)
dropdown_two = forms.ChoiceField(
label="Category",
widget=forms.Select(attrs={"class": "selecter form-control"}),
choices=[(None, '...')],
required=True
)
Then use this form in views.py like so:
my_form = MyForm(initial={})
return render(request,{'my_form':my_form})
Then finally in html file:
{{my_form.media}}
{% for item in my_form %}
<div class="form-group col-lg-2" id="dropdown-content">
{{item.label_tag}}
{{item}}
</div>
{% endfor %}
</div>
For more refer to this:
https://docs.djangoproject.com/en/4.0/topics/forms/

create a default in one Model using values from another Model in Django

I have been struggling over this for days diving down stackoverflow rabbit holes, documentation, and youtube tutorials. I'm just running in circles at this point. So...
I have two models Variables and Entry. The daily inputs for Entry are to be recordings associated with a given Variable. Ex. I want to track daily sleep as a variable. Then, using that variable, have daily data entry associated with that variable using the Entry model.
My models are below... (I suspect my schema is a mess as well, but it's generally working. This is my first time)
class Variables(models.Model):
ENTRY_TYPE_CHOICES = [
('numeric', 'enter a daily number'),
('scale', 'rate daily on a scale of 1-10'),
('binary', "enter daily, 'yes' or 'no' "),
]
id = models.IntegerField(primary_key=True)
dep_var = models.CharField(max_length=50, default='')
dv_reminder = models.CharField(max_length=50, choices=ENTRY_TYPE_CHOICES, default="numeric")
# id current user
evoler = models.ForeignKey(get_user_model(), default='', on_delete=models.CASCADE)
def __str__(self):
return self.dep_var
def get_absolute_url(self):
return reverse('entry_new')
class Entry(models.Model):
id = models.AutoField(primary_key=True)
evoler = models.ForeignKey(get_user_model(), default='', on_delete=models.CASCADE) # id the active user
dep_variables = models.CharField(max_length=50, default = '')
data = models.FloatField(default=0.0)
date = models.DateField(default=datetime.date.today)
I've tried writing a function that would identify the most recent variable from a given user and to use that as the default value in the Entry.dep_variables model. That works in the local environment but causes issues when I try to migrate the database.
Views...
def daily_entry(request):
''' page to make daily entries '''
if request.method != 'POST':
# No data submitted. GET submitted. Create a blank form
form = DailyEntryForm()
else:
#POST data submitted. Process data
form = DailyEntryForm(data=request.POST)
if form.is_valid():
data = form.save(commit=False)
data.evoler = request.user
data.save()
return HttpResponseRedirect(reverse('entry_new'))
context = {'form': form}
return render(request, 'entry_new.html', context)
Forms...
class VariablesForm(forms.ModelForm):
class Meta:
model = Variables
fields = ['dep_var', 'dv_reminder' ]
labels = {'dep_var':'Dependent variable to track', 'dv_reminder': 'Type of measure'}
class DailyEntryForm(forms.ModelForm):
class Meta:
model = Entry
var = Variables.dep_var
fields = ['dep_variables', 'data', 'date']
labels = {'dep_variables': 'Dependent variable you are tracking',
'data': 'Daily entry', 'date': 'Date'}
and template.html...
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<br>
<h1>New Entry</h1>
<form class="" action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" name="" value="Save" />
</form>
{% endblock content %}
Any and all assistance would be infinitely appreciated.

Increment a value in models.py and website behaves accordingly

I am new to Django and I've got the hang of the basics so far but I am trying to do something that the tutorials I learnt from haven't taught me and basically what I want to do is, I have a field in my models.py called delegates_num and that field is a counter for the number of delegates which sign up for a particular course. I want to be able to increment that field by 1 each time someone signs up for a particular course, the courses being [ITIL, Change Management, Management of Risk, Programme Management, PRINCE2]
So for example, if the user books an ITIL course, the counter for that course will be incremented by 1. Each course has a limit of 15 spaces so a condition somewhere which says something like:
if course.name = 'ITIL' && if delegates_num > 15
redirect user to 'course is full page'
else submit registration form and increment delegates_num by 1
I would be extremely grateful for any help, here's the code so far:
class Course(models.Model):
MY_CHOICES = (
('Open', 'Open'),
('Closed', 'Closed'),
('Fully Booked', 'Fully Booked'),
)
course_name = models.CharField(max_length=40)
course_code = models.CharField(max_length=40)
price = models.CharField(max_length=40, default='add price')
topic_details = models.TextField(max_length=200)
start_date = models.DateField('start date')
end_date = models.DateField('end date')
status = models.CharField(max_length=20, choices=MY_CHOICES)
venue = models.ForeignKey(Venue, on_delete=models.CASCADE)
room = models.CharField(max_length=20)
delegates_num=models.IntegerField()
def add_delegate(self):
#for count, thing in enumerate(args):
self.delegates_num+=1
def __str__(self):
return self.course_name
models.py
<h1>Registration</h1>
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
{% if course.course_name = 'ITIL' %}
{{ course.delegates_num|inc }}
{% if course.delegates_num > 15 %}
<meta http-equiv="refresh" content="1;url=http://example.com">
<script type="text/javascript">
window.location.href = "https://yr4-group-project-mfblack.c9users.io/sorry_full/"
</script>
{% endif %}
{% endif %}
<button type="submit" class="save btn btn-default">Save</button>
</form>
book_course.html
def book_course(request):
if request.method == "POST":
form = StudentForm(request.POST)
if form.is_valid():
student = form.save(commit=False)
student.save()
student.course.add_delegate()
return redirect('registration_complete')
else:
form = StudentForm()
return render(request, 'website/book_course.html', {'form': form})
views.py
It's probably much easier to just make a property, since I'm guessing you're not taking into account people leaving the course - or the possibility of user error.
A property that retrieves a count is usually a small database operation and has some guarrantee to be accurate
#property
def delegates_num(self)
return self.user_set.count()
I assume you have a fk to a user model or simlar..

How do I avoid "record already exists" form validation error using ModelForms in Django 1.6?

Following the ModelForm docs and using this model:
class ShippingLabel(models.Model):
"""Record what shipping lables were printed list"""
class Meta:
db_table = 'shipping_labels'
ordering = ('client',)
verbose_name = _('shipping label')
verbose_name_plural = _('shipping labels')
LAYOUT_LASER_2x2 = "1"
LAYOUT_TICKET = "2"
LAYOUT_LASER_1x1 = "3"
LAYOUT_CHOICES = (
( LAYOUT_LASER_1x1, _("Laser (1x1 sheet)") ),
( LAYOUT_LASER_2x2, _("Laser (2x2 sheet)") ),
( LAYOUT_TICKET, _("Ticket (3-inch wide)") ),
)
client = models.ForeignKey(Company, blank=False, null=False, unique=True, help_text=_("Which Client to ship to?"), verbose_name=_("client") )
store = models.ForeignKey(Store, blank=False, null=False, help_text=_("What store info should be used? (address, logo, phone, etc)"), verbose_name=_("store") )
packages = models.CharField(_("Packages"), max_length=30, blank=False, null=False, help_text=_("Total number of packages. One label printed per package.") )
preprinted_form = models.BooleanField(_("Pre-Printed Form"), default=False, help_text=_("Are you using pre-printed shipping label stickers?"), )
layout = models.CharField(_("Record Type"), max_length=10, blank=False, null=False, choices=LAYOUT_CHOICES, default=LAYOUT_LASER_1x1, help_text=_("Print on large labels (4 per Letter page), Laser large labels (1 per page), or ticket printer?") )
added_by = models.CharField(_("Added By"), max_length=30, blank=True, null=True, help_text=_("The User that created this order.") )
date_added = models.DateTimeField(_('Date added'), auto_now_add=True)
date_modified = models.DateTimeField(_('Date modified'), auto_now=True)
def get_absolute_url(self):
return reverse('shipping:printship', args=[str(self.id)])
def __unicode__(self):
return unicode(self.client)
I made this form template following their example (manual_label.html):
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load staticfiles %}
{% block extrahead %}
{{ block.super}}
<script src="{{ STATIC_URL }}js/jquery-1.11.1.js"></script>
{% endblock %}
{% block content %}
<form id="manual_label" method="post" action="">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="generar etiquetas autoadhesivas"/>
</form>
<p>
</p>
{% endblock %}
My app urls.py:
from django.conf.urls import patterns, url
from shipping.views import printship, pcustomer, manual_label
urlpatterns = patterns('',
url(r'pcust/', pcustomer, name='pcustomer'),
url(r'mlabel/([0-9]+)/$', manual_label, name='manual_label'),
url(r'printlabel/([0-9]+)/$', printship, name='printship'),
)
My view (with lots of diagnostic logging):
#login_required()
def manual_label(request, id):
logger.debug("SHIPPING.VIEWS.manual_label")
if request.method == 'POST':
logger.debug("SHIPPING.VIEWS.manual_label: POST!")
client = get_object_or_404(Company, pk=id)
labelset = ShippingLabel.objects.filter(client=client)
if len(labelset)>0:
# Pre-existing label, update it:
logger.debug("SHIPPING.VIEWS.manual_label.POST: Update a label!")
label = labelset[0]
form = ShipLabelForm(request.POST, instance=label)
else:
# New label:
logger.debug("SHIPPING.VIEWS.manual_label.POST: Save New label!")
form = ShipLabelForm(request.POST)
if form.is_valid():
logger.debug("SHIPPING.VIEWS.manual_label.POST: form is valid")
label = form.save(commit=True)
logger.debug("SHIPPING.VIEWS.manual_label.POST: label pk: " + str(label.id) )
logger.debug("SHIPPING.VIEWS.manual_label.POST: label client name: " + str(label.client.name) )
logger.debug("SHIPPING.VIEWS.manual_label: post return")
return HttpResponseRedirect(reverse('shipping:printship', args=[str(label.id)]))
else:
logger.debug("SHIPPING.VIEWS.manual_label: GET!")
client = get_object_or_404(Company, pk=id)
labelset = ShippingLabel.objects.filter(client=client)
if len(labelset)>0:
# Pre-existing label, load it:
logger.debug("SHIPPING.VIEWS.manual_label: Pre-Existing label, load it...")
label = labelset[0]
form = ShipLabelForm(instance=label)
else:
# New label:
label = ShippingLabel(client=client,
store=request.user.employee.store,
added_by=request.user.get_username())
form = ShipLabelForm(instance=label)
logger.debug("SHIPPING.VIEWS.manual_label: get return")
return render(request, 'shipping/manual_label.html', {
'title': u"Creación de etiquetas Manual Envios",
'form': form,
})
My forms.py definition:
class ShipLabelForm(ModelForm):
class Meta:
model = ShippingLabel
localized_fields = '__all__'
fields = '__all__'
widgets = {
'added_by': HiddenInput,
'id': HiddenInput,
}
I added 'id': HiddenInput, to try and "force" record ID number to get sent out to the form, in the theory that my error occurs because without the ID number, Django will validate in "ADD" mode which will certainly trigger the "unique" flag I have on clients.
The manual_label view is called by a customer selection form, passing in the client id. The goal is to generate an ADD form if there is currently no shipping label for this client defined - which works.
And if a shipping label already exists, I pre-load the form with its data. The idea being I thought the form system would automatically do an UPDATE on the existing record.
In either case, the saved shipping label record is used to generate the shipping labels desired.
This works in the admin view (using view on site). But I wanted to give the users a simpler system. This works fine for ADDing new labels. But when I try to EDIT an existing label, I get a form validation error "client already exists".
It seemed like such an easy thing to do....
So, what am I missing tor doing wrong?
You should be using the instance argument when initializing the form, both in the POST and GET blocks.

Categories