Comparison of the string with the data in the database - python

I would like to compare a sentence which I input to my code with any value in database.
There is my function which apply data into database from my page:
def create_author(request):
form_author = AuthorForm()
context = {'form_author': form_author}
if request.method == 'POST':
form_author = AuthorForm(request.POST)
if form_author.is_valid():
name = request.POST.get('name',)
surname = request.POST.get('surname')
if name == Author.name and surname == Author.surname:
print("We have this author in database")
# There should be stop.
else:
author_object = Author(name=name, surname=surname)
author_object.save()
return render(request, 'authors/create_author.html', context)
and it works but it only adds - doesn't check if any author exist in db.
Any ideas for fixing it? Thanks in advice.

You can use exists().
Instead of this
if name == Author.name and surname == Author.surname:
print("We have this author in database")
Try this
if Author.objects.filter(name=name, surname=surname).exists():
print("We have this author in database")

You can use get_or_create [Django-doc] here, like:
def create_author(request):
form_author = AuthorForm()
context = {'form_author': form_author}
if request.method == 'POST':
form_author = AuthorForm(request.POST)
if form_author.is_valid():
name = form_author.cleaned_data['name']
surname = form_author.cleaned_data['surname']
__, created = Author.objects.get_or_create(name=name, surname=surname)
if not created:
print("We have this author in database")
# There should be stop.
return render(request, 'authors/create_author.html', context)
We here will thus create an Author object, with the given name and surname, given such author does not yet exists. If it already exists, we retrieve it, but that is not that much of a problem.
Note that in case the POST is successful, you better use a redirect here, this is the Post/Redirect/Get [wiki] architectural pattern.
You also better use the cleaned_data of your form_author, instead of using the request.POST data directly, since that is cleaned. Finally in case AuthorForm is a ModelForm [Django-doc], you better let .save() [Django-doc] do the required work.

Related

Django: Pass a variable/parameter to form from view? [duplicate]

I have a Model as follows:
class TankJournal(models.Model):
user = models.ForeignKey(User)
tank = models.ForeignKey(TankProfile)
ts = models.IntegerField(max_length=15)
title = models.CharField(max_length=50)
body = models.TextField()
I also have a model form for the above model as follows:
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput())
class Meta:
model = TankJournal
exclude = ('user','ts')
I want to know how to set the default value for that tank hidden field. Here is my function to show/save the form so far:
def addJournal(request, id=0):
if not request.user.is_authenticated():
return HttpResponseRedirect('/')
# checking if they own the tank
from django.contrib.auth.models import User
user = User.objects.get(pk=request.session['id'])
if request.method == 'POST':
form = JournalForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
# setting the user and ts
from time import time
obj.ts = int(time())
obj.user = user
obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])
# saving the test
obj.save()
else:
form = JournalForm()
try:
tank = TankProfile.objects.get(user=user, id=id)
except TankProfile.DoesNotExist:
return HttpResponseRedirect('/error/')
You can use Form.initial, which is explained here.
You have two options either populate the value when calling form constructor:
form = JournalForm(initial={'tank': 123})
or set the value in the form definition:
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
Other solution: Set initial after creating the form:
form.fields['tank'].initial = 123
If you are creating modelform from POST values initial can be assigned this way:
form = SomeModelForm(request.POST, initial={"option": "10"})
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values
I had this other solution (I'm posting it in case someone else as me is using the following method from the model):
class onlyUserIsActiveField(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
self.fields['is_active'].initial = False
class Meta:
model = User
fields = ['is_active']
labels = {'is_active': 'Is Active'}
widgets = {
'is_active': forms.CheckboxInput( attrs={
'class': 'form-control bootstrap-switch',
'data-size': 'mini',
'data-on-color': 'success',
'data-on-text': 'Active',
'data-off-color': 'danger',
'data-off-text': 'Inactive',
'name': 'is_active',
})
}
The initial is definded on the __init__ function as self.fields['is_active'].initial = False
As explained in Django docs, initial is not default.
The initial value of a field is intended to be displayed in an HTML . But if the user delete this value, and finally send back a blank value for this field, the initial value is lost. So you do not obtain what is expected by a default behaviour.
The default behaviour is : the value that validation process will take if data argument do not contain any value for the field.
To implement that, a straightforward way is to combine initial and clean_<field>():
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
(...)
def clean_tank(self):
if not self['tank'].html_name in self.data:
return self.fields['tank'].initial
return self.cleaned_data['tank']
If you want to add initial value and post other value you have to add the following :
or None after request.POST
form = JournalForm(request.POST or None,initial={'tank': 123})
If you want to add files or images also
form = JournalForm(request.POST or None,request.FILES or None,initial={'tank': 123})
I hope this can help you:
form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id
I also encountered the need to set default values in the form during development. My solution is
initial={"":""}
form=ArticleModel(request.POST)
if form.has_changed():
data = {i: form.cleaned_data[i] for i in form.changed_data}
data.update({key: val for key, val in init_praram.items() if key not in form.changed_data})
use form.has_changed ,if form.fields is required you can use this method
How I added the initial to the form:
I read #Sergey Golovchenko answer.
So I just added it to the form in if request.method == 'POST':.
But that's not where you place it, if you want to see what value it got before posting the form.
You need to put it in the form where the else is.
Example here from views.py
def myForm(request):
kontext = {}
if request.method == 'POST':
# You might want to use clean_data instead of initial here. I found something on a stack overflow question, and you add clean data to the Forms.py, if you want to change the post data. https://stackoverflow.com/questions/36711229/django-forms-clean-data
form = myModelForm(request.POST, initial={'user': request.user})
if form.is_valid():
form.save()
return redirect('/')
else:
# you need to put initial here, if you want to see the value before you post it
form = myModelForm(initial={'user': request.user})
kontext['form'] = form
return render(request, 'app1/my_form.html', kontext)

Assigning the correct ID to a form?

So I'm expanding on the official tutorial, and I'm trying to let a user create their own poll. I'm having trouble assigning the correct question_id to the choice, so the choice aligns in the database with the question and both can be read off. Here is my view:
def poll_create(request):
if request.method == "POST":
Qform = QuestionForm(request.POST)
Cform = ChoiceForm(request.POST)
if Qform.is_valid():
poll = Qform.save(commit=False)
poll.author = request.user
poll.pub_date = timezone.now()
poll.save()
if Cform.is_valid():
poll = Cform.save(commit=False)
poll.author = request.user
findid = Question.objects.all().order_by("-id")[0] ##Finds the id of the last question in database
poll.question_id = findid.id + 1
poll.save()
return redirect('polls:detail', pk=poll.pk)
else:
Qform = QuestionForm()
Cform = ChoiceForm()
return render(request, 'polls/create.html', {'Qform': Qform, 'Cform': Cform})
So the idea is to have a question form (Qform) which writes the question to the database, and then below on the webpage a choice form (Cform), which writes the answer to the database. I'm really confused about applying a question_id to the Cform. At the moment, I have this line:
findid = Question.objects.all().order_by("-id")[0] ##Finds the id of the last question in database
poll.question_id = findid.id + 1
Which seems like a very hacky attempt to find the last id and assign it to the next one. It doesnt line up because the poll.pk has a different value. I'm at a loss here and don't really understand what's going on. Any help would be appreciated.
Your code is a bit confusing because you are using the variable poll for questions and choices. It would be better to use question and choice instead.
You should check that both forms are valid before you start saving, otherwise you can end up with a question without a choice if the question form is valid but the choice form is invalid.
After you have saved the question, you can get the id with question.id, and you can assign the question to the choice object. There is no need to do a query to find the latest question id.
Putting that together, you have something like:
if Qform.is_valid() and Cform.is_valid():
question = Qform.save(commit=False)
question.author = request.user
question.pub_date = timezone.now()
question.save()
choice = Cform.save(commit=False)
choice.author = request.user
choice.question = question
choice.save()
return redirect('polls:detail', pk=question.pk)
Note also that it's recommended to use lowercase question_form and choice_form, for the form instances, and uppercase QuestionForm and ChoiceForm for the classes.

Using request in django model

I've got 2 models
class Post(models.Model):
user = models.ForeignKey(User, verbose_name='User')
content = models.TextField(verbose_name='Text', max_length=4000)
date = models.DateTimeField(verbose_name='Date', default=now())
class Vote(models.Model):
vote = models.IntegerField(choices=VOTE, verbose_name='Vote')
post = models.ForeignKey(Post, verbose_name='Post')
user = models.ForeignKey(User, verbose_name='User')
and view which load last 15 posts:
posts = Post.objects.all().order_by('-date')[:15]
Now I want to have information about active user vote in all of my queryset objects
I thought about custom method in Post model which will check logged user and get vote objects:
def user_vote(self):
try:
data = Vote.objects.filter(post=self, user=request.user)
return data.vote
except ObjectDoesNotExist:
#not voted
But it seems django dont allow to use request in model.
Any other ideas?
You can pass user as argument to method like this:
def user_vote(self, user):
also I guess you need to get a Vote instance, not queryset, so you should user .get method instead .filter:
def user_vote(self, user):
try:
data = Vote.objects.get(post=self, user=user)
return data.vote
except ObjectDoesNotExist:
#not voted
then you can call this method with Post instance:
post.user_vote(request.user)
UPDATE
Django not allow to use method with arguments in template. So in your case better to refactor this method into templatetag:
def get_user_vote(post, user):
try:
data = Vote.objects.get(post=post, user=user)
return data.vote
except ObjectDoesNotExist:
#not voted
You can find manual here https://stackoverflow.com/a/6493001/3291969
don't forget to register it :)
That's not a django problem, it's because request isn't anywhere in the scope of your code. If you pass request to your model's method it will work. Something like:
def user_vote(self, request):
try:
data = Vote.objects.get(post=self, user=request.user)
return data.vote
except Vote.DoesNotExist:
#not voted
and call it like this with your Post instance:
# Note the request being passed as a parameter
vote = post.user_vote(request)
UPDATE:
To get all votes from a user you could do something like this:
votes = Vote.objects.filter(post=self, user=request.user)
return reduce(lambda x, y: x.vote + y.vote, votes, 0)
we set a 0 at the end, so in cases where there's no votes from this user, we'll get a 0 as a return.
This will sum every vote and return it.
If you don't want to sum these votes, change the line:
return reduce(lambda x, y: x.vote + y.vote, votes, 0)
to:
return map(lambda x, y: x.vote + y.vote, votes)
and this will get you a list with all the votes from the request.user user
I think you're looking for this package:
https://pypi.python.org/pypi/django-crequest/1.0
Description:
crequest will bring you current request object of your django application from anywhere in your code.
And it is used like this:
from crequest.middleware import CrequestMiddleware
current_request = CrequestMiddleware.get_request()

django get_or_create method always results in a new record

Model
class projects(models.Model):
"""Table that holds the details of the projects."""
toiName = models.CharField(max_length=100)
toiOwner = models.CharField(max_length=50)
receiver = models.CharField(max_length=50)
manager = models.CharField(max_length=50)
toiOwnerEmail = models.EmailField(max_length=70)
receiverEmail = models.EmailField(max_length=70)
managerEmail = models.EmailField(max_length=70)
dateUpdated= models.DateTimeField(default=datetime.today())
dateCreated = models.DateTimeField(default=datetime.today())
class Meta:
db_table="projects"
View, the original code to save the model works fine, when I go ahead and edit the form in the view, I always end up with a new record.
data = model_to_dict(projects.objects.filter(toiName=pid, managerEmail=request.user)[0])
if request.method == 'POST':
form = projectsForm(request.POST)
if form.is_valid():
#form = projectsForm(request.POST, instance=projects.objects.get(toiName=pid))
#obj = projects\
obj, created = projects.objects.get_or_create\
(toiName=request.POST['toiName'],
toiOwnerEmail=request.POST['toiOwnerEmail'],
toiOwner=request.POST['toiOwner'],
manager=request.POST['manager'],
receiver=request.POST['receiver'],
receiverEmail=request.POST['receiverEmail'],
dateUpdated=datetime.now(),
dateCreated=data['dateCreated'],
managerEmail=request.user,)
Here created always results in True.
At least this dateUpdated=datetime.now() causes get_or_create to always create new record, because each time datetime.now() is different.
I believe I was using the get_or_create incorrectly, since I was only trying to update the entry.
I fixed the code in the view with:
data = model_to_dict(projects.objects.filter(toiName=pid, managerEmail=request.user)[0])
proj = projects.objects.get(toiName=pid, managerEmail=request.user)
if request.method == 'POST':
form = projectsForm(request.POST)
if form.is_valid():
proj.toiName=form.cleaned_data['toiName']
proj.toiOwnerEmail=form.cleaned_data['toiOwnerEmail']
proj.toiOwner=form.cleaned_data['toiOwner']
proj.manager=form.cleaned_data['manager']
proj.receiver=form.cleaned_data['receiver']
proj.receiverEmail=form.cleaned_data['receiverEmail']
proj.dateUpdated=datetime.now()
#proj.dateCreated=data['dateCreated']
proj.save()
additional to #user1865366 answer, projects.objects.get should be enclose it with try ... except ... like so
try:
proj = Projects.objects.get(toiName=pid,manageEmail=request.user)
except Projects.DoesNotExist :
# do something create new proj and do something with the form
...
otherwise there will be big error screen when django cannot get the object

Multiple linked Django forms, one submit

I have models for Application and Role. Role is linked to a FK Role_type, which is linked by FK to Applications that can use those Role_types (this is a bit of an over-simplication for the question, but I think it suffices). I need a way to create a form to make a new Application, and also to create records assigning associated roles to people (although they can be left blank.)
I have gotten as far as creating the form for the Application and having the associated Role-Types appear on the page, with dropdowns to be populated with a user. Hitting submit, though, didn't create any of the associated Role records. All of my research seems to keep coming back to Inline Model Forms, but the docs aren't really making sense to me--the inputs in the example don't seem to correlate to what I need.
I know this may seem like a duplicate, but trust me when I say I've looked at every SO question that seems to relate to this!
EDIT: My POST looks like this: QueryDict: {u'roles-MAX_NUM_FORMS': [u'1000'], u'roles-1-role_type': [u'4'], u'roles-0-user': [u'1'], u'app-owner': [u'1'], u'app-name': [u'1234'], u'app-serviceTier': [u''], u'app-jiraProject': [u''], u'roles-TOTAL_FORMS': [u'2'], u'roles-1-user': [u''], u'roles-0-role_type': [u'3'], u'csrfmiddlewaretoken': [u'eGsDwtsSQJfl0'], u'roles-INITIAL_FORMS': [u'2']}>. Printing RolesFormSet gives me the exact same output (see comment below)
models.py
class Item(models.model):
name = models.CharField(max_length=255)
roles = models.ManyToManyField(User, through='Role')
class Application(Item):
other_assorted_attributes = foo
class RoleType(models.Model):
name = models.CharField(max_length=255)
class ItemTypeRoleMapping(models.Model):
''' pairs role-types (e.g., Developer) with an Item class they are relevant to'''
roleType = models.ForeignKey(RoleType)
itemType = models.CharField(max_length=255, choices=itemChoices)
class Role(models.Model):
role_type = models.ForeignKey(RoleType)
user = models.ForeignKey(User)
item = models.ForeignKey(Item)
views.py
def buildRolesFormset(itemClass):
''' given an item, build a form for all associated roles '''
roleTypesForItem = ItemTypeRoleMapping.objects.all().filter(itemType=itemClass.__name__)
applicable_roles = [{'role_type': roleType} for roleType in roleTypesForItem]
# formset = rolesFormSet(initial=initial, prefix='roles')
RoleFormSet = inlineformset_factory(Application, Role, extra=len(roleTypesForItem), can_delete=False)
formset = RoleFormSet()
for subform, data in zip(formset.forms, applicable_roles):
subform.initial = data
return formset
def new(request):
''' Create a new application '''
user = request.user
# check permission
if request.method == 'POST':
appform = AppForm(request.POST, prefix='app')
if appform.is_valid():
app = appform.save(commit=False)
rolesInlineFormSet = inlineformset_factory(Application, Role)
# pdb.set_trace()
rolesFormSet = rolesInlineFormSet(request.POST, instance=app, prefix='roles')
if rolesFormSet.is_valid():
rolesFormSet.save()
else:
print rolesFormSet.errors
app = appform.save()
# check rolesFormSet
return redirect(reverse('index'))
else:
appform = AppForm(prefix='app')
rolesFormSet = buildRolesFormset(Application)
return render(request, 'who/editapp.html',
{'appform': appform,
'rolesFormSet': rolesFormSet
})
Tricky to tell without more information, but it looks like you're not saving your rolesFormset in the view. You need to call rolesFormset.save() alongside your form.save() call. Additionally, I suppose you want to attach the roles to the created app? Something like this in your view should work:
if request.method == 'POST':
form = AppForm(request.POST)
rolesFormset = RoleForm(request.POST)
if form.is_valid() and rolesFormset.is_valid():
app = form.save()
roles = rolesFormset.save()
for role in roles:
app.roles.add(role)
return redirect(reverse('index'))
Update: Presuming the models.py is out-of-date, and Role does in fact have a foreignKey to User, the problem will be that you're setting a prefix here:
rolesFormSet = rolesInlineFormSet(request.POST, instance=app, prefix='roles')
but not in your buildRolesFormset function. In that function, do:
formset = RoleFormSet(prefix='roles')

Categories

Resources