How check if input element is already in query in Flask? - flask

user input some tags, I have to chack if it is alredy in query and if not I save it. I have 2 different base, one for post, another for tag, and then I create post I use Tag bases objects. and if my post tag isnot in Tag's base I create new record for it.
if tag_name not in tags:
new_tag = Tag(tag_name, user)
db.session.add(new_tag)
db.session.commit()
this is how check and create new record but actually it doesnt work properly.
this is whole function:
def get_user(user_id):
user = User.query.filter_by(id = user_id).first()
tags = Tag.query.order_by(Tag.date_created).all()
# posts = Post.query.order_by(Post.date_created).all()
form = questionForm()
total_likes = 0
if user.posts:
for likes in user.posts:
total_likes+=1
if form.validate_on_submit():
user = current_user.id
tag_name = request.form.get('tag_name')
if tag_name not in tags:
new_tag = Tag(tag_name, user)
db.session.add(new_tag)
db.session.commit()
post = Post(form.heading.data, form.text.data, user, tag_name)
db.session.add(post)
db.session.commit()
flash('posted succesfuly')
return render_template("profile.html", user = user, form=form, total_likes = total_likes,tags = tags)
return render_template("profile.html", user = user, form=form, total_likes = total_likes, tags = tags)
whats my Tag class:
class Tag(db.Model):
__tablename__='tag'
id =db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(15), nullable = False, unique=True, index=True)
date_created = db.Column(db.DateTime, default = datetime.utcnow())
author = db.Column(db.Integer, db.ForeignKey('user.id', ondelete="CASCADE"), nullable=False)
def __init__(self, name, author, date_created = datetime.utcnow()):
self.name=name
self.author = author
my form class :
class questionUpdateForm(FlaskForm):
heading = StringField('heading', [Length(min=2, max=50),
DataRequired(message='Question ')])
# tag = StringField('Programming Language')
text = StringField('Question', [Length(min=2, max=1000),
DataRequired(message='description')])
and jinja template :
<div >
<label for="states">Choose or Create Tag</label>
<input class="form-control" type="text"name='tag_name' id="tag_name" name="states" list="states-list" value={{update_post.tags}}>
<datalist id="states-list">
{%for tag in tags%}
<option>{{tag.name}}</option>
{%endfor%}
</datalist>
</div>

What you need to do is something like this:
if tag_name not in {tag.name for tag in tags}:
new_tag = Tag(tag_name, user)
db.session.add(new_tag)
db.session.commit()
because right now you are just searching if the given name is in the tag objects, which doesn't really make sense.
This will search if the tag_name is in the set of all distinct existing tag names.

Related

Django & Form with SelectMultiple: null value in column x of relation y violates not-null constraint

I am facing the following error when trying to save the project after filling the form where i am choosing multiple tags for this project:
null value in column "tag_id" of relation "project_tags" violates not-null constraint
DETAIL: Failing row contains (10263, 10262, null). --> project_tags(id, project_id, tag_id)
The db model is simple: I have projects, and each project has tag(s). All is defined by the following models:
class Project(models.Model):
id = models.AutoField(primary_key=True)
client = models.ForeignKey(User, on_delete=models.CASCADE)
start_date = models.DateField()
end_date = models.DateField()
class Meta:
managed = False
db_table = 'project'
def get_absolute_url(self):
return reverse('project-detail', kwargs={'pk': self.pk})
class ProjectTag(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=30)
class Meta:
managed = False
db_table = 'project_tag'
def __str__(self):
return self.name
class ProjectTags(models.Model):
id = models.AutoField(primary_key=True)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
tag = models.ManyToManyField(ProjectTag)
class Meta:
managed = False
db_table = 'project_tags'
View is following:
#login_required
def add_project(request):
submitted = False
if request.method == "POST":
form1 = ProjectForm(request.POST)
form2 = ProjectTagsForm(request.POST)
if form1.is_valid() and form2.is_valid():
form1_part = form1.save(commit=False)
form1_part.client = request.user
form1_part.save()
project_id = Project.objects.get(id=form1_part.id)
form2_part = form2.save(commit=False)
form2_part.project = project_id
form2_part.save()
return HttpResponseRedirect('/project/new?submitted=True')
else:
form1 = ProjectForm
form2 = ProjectTagsForm
if 'submitted' in request.GET:
submitted = True
context = {'form1':form1
,'form2':form2
,'submitted':submitted
}
return render(request, 'home_page/add_project.html',context)
WIth following forms that are both in one template:
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ('start_date', 'end_date')
def __init__(self, *args, **kwargs):
super(ProjectForm, self).__init__(*args, **kwargs)
class ProjectTagsForm(forms.ModelForm):
class Meta:
model = ProjectTags
fields = ('tag',)
widgets = {
'tag': forms.SelectMultiple(attrs={'class': 'form-control','size': 12})
}
{% if submitted %}
Your project was submitted successfully!
{% else %}
<form action="" method=POST>
{% csrf_token %}
{{ form1.as_p }}
{{ form2 }}
<input type="submit" value="submit me" class="btn btn-secondary">
I understand the problem that after submitting the form it is not able to convert the selected tag names into tag_ids to fill the records (id,project_id,tag_id) and insert them to db table (as the table doesnt allow nulls as tag_id), but I have no idea how to fix, especially when it is practically copy paste of this Codemy video and its script where it worked https://youtu.be/x99hW1N8Nug

How to query a user's display information in the AccountDisplayInformation from the AccountModel

Account is my AUTH_USER_MODEL and AccountDisplayInfo consists of all the additional display info of every account. So they can input and submit, and subsequently update their information. These are my codes, but I'm unsure why it isn't working. First of all, I am receiving this error:
DoesNotExist at /account/5/displayinfo/ AccountDisplayInfo matching query does not exist.
Secondly, the "update" function isn't working.
models.py
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
class AccountDisplayInfo(models.Model):
account = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
instagram = models.CharField(max_length=50, unique=True, blank=True, null=True) #instagram
.html
<form method="POST" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<div class="d-flex justify-content-center">
<button type="submit" class="btn btn-primary btn-sm col-lg-5">Update</button>
</div>
</form>
views.py
def display_information_view(request, *args, **kwargs):
user_id = kwargs.get("user_id")
account = Account.objects.get(pk=user_id)
context = {}
displayinfo = AccountDisplayInfo.objects.get(account=account)
if request.POST:
form = DisplayInformationForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
info = form.save(commit=False)
info.account = request.user
info.save()
messages.success(request, 'Your profile display information have been updated', extra_tags='editdisplayinfo')
return redirect("account:view", user_id=account.pk)
else:
form = DisplayInformationForm(request.POST, instance=request.user,
initial={
"instagram": displayinfo.instagram,
}
)
context['form'] = form
else:
form = DisplayInformationForm(
initial={
"instagram": displayinfo.instagram,
}
)
context['form'] = form
return render(request, "account/displayinfo.html", context)
forms.py
class DisplayInformationForm(forms.ModelForm):
class Meta:
model = AccountDisplayInfo
fields = ('instagram')
Also, would be great if you can advise on this::
If I have 2 tables. Table 1 and Table 2. Table 2 has a foreign key to table 1 but table 1 dont have a foreign key to table 2. How can I query table 2's data from table 1? Thanks
By default .get() will return a DoesNotExist exception if no object matches the query you executed and stop the code from running, so if you want to input it manually on the same page use filter instead:
displayinfo = AccountDisplayInfo.objects.filter(account=account).first()
Then in your template do something like this:
{% if displayinfo %}
... show display info...
{% else %}
<p> No info yet </p> <!-- (or show some form) -->
{% endif %}
To answer your other question:
You have to use the related_name or related models attribute to access the ForeignKey data or use the model name with the _set suffix, for example:
class Post(models.Model):
title = models.CharField(max_lenght=10)
class Comment(models.Model):
body = models.CharField(max_lenght=200)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
then you would get the Post and its comments:
post = Post.objects.get(pk=1)
comments = post.comments.all()
if you didn't have the related_name attribute in your model field you would do this instead:
comments = post.comment_set.all()
UPDATE
Maybe the issue is in your Form class, try removing the save method from it and instead do this in your view:
if request.POST:
form = DisplayInformationForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
info = form.save(commit=False)
info.account = request.user
messages.success(request, 'Your profile display information have been updated', extra_tags='editdisplayinfo')
info.save()
return redirect("account:view", user_id=account.pk)

Django how to add taggit tags to model within template

I have a Django app that has a list of companies, and when the user clicks on a company they are presented with all of the details of that company. Now I'm trying to add a tag feature so any use can add tags to the company which they'll also be able to search on. I've created the form and the template stuff, but now I'm stuck now on how to wire it into the View, specifically updating the Company model with the new tag(s).
Forms.py
class TagForm(forms.Form):
tag = forms.CharField(label='Tag', max_length=100)
class Meta:
model = Company
field = 'tag'
Template
<div class="add-tag-form">
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default btn-sm">Add</button>
</form>
</div>
View
class CompanyDetails(generic.DetailView):
model = Company
template_name = 'company_details.html'
# This was my attempt to work it into the View...
def post(self, request, *args, **kwargs):
form = TagForm(request.POST)
if form.is_valid():
tag = form.save(commit=False)
tag.company = Company.objects.get(pk=pk)
tag.save()
def get_context_data(self, **kwargs):
pk = self.kwargs.get('pk')
context = super(CompanyDetails, self).get_context_data(**kwargs)
context['articles'] = Articles.objects.filter(company_id=pk).order_by('-date')
context['transcripts'] = Transcripts.objects.filter(company_id=pk).order_by('-date')
context['form'] = TagForm()
# Yahoo Finance API data
stock_symbol = self.object.stock_symbol
data = Share(stock_symbol)
stock_open = data.get_open()
year_range = data.get_year_range()
fifty_day_moving_average = data.get_50day_moving_avg()
market_cap = data.get_market_cap()
yahoo_finance = dict()
yahoo_finance['stock_open'] = stock_open
yahoo_finance['year_range'] = year_range
yahoo_finance['fifty_day_moving_average'] = fifty_day_moving_average
yahoo_finance['market_cap'] = market_cap
context['yahoo_finance'] = yahoo_finance
# Yahoo News RSS data
yahoo_news = feedparser.parse("http://finance.yahoo.com/rss/headline?s=" + stock_symbol)
yahoo_news = yahoo_news['entries']
for item in yahoo_news:
item['published'] = datetime.strptime(item['published'], '%a, %d %b %Y %H:%M:%S %z')
context['yahoo_news'] = yahoo_news
return context
UPDATE
The error I get "'TagForm' object has no attribute 'save'". When I change the form from forms.Form to forms.FormModel I get the following error "Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited; form TagForm needs updating.". I'm not trying to create a model, rather update it through the form.
Taggit is used in the Model
class Company(models.Model):
company_name = models.CharField(max_length=200)
tags = TaggableManager()
One thing that you can do is to make a simple form for the tag, just like what you did but remove the Meta information and update the post method to just add the tag in the company. Something like below:
# forms.py
class TagForm(forms.Form):
tag = forms.CharField(label='Tag', max_length=100)
# views.py
class CompanyDetails(generic.DetailView):
...
# This was my attempt to work it into the View...
def post(self, request, *args, **kwargs):
company = self.get_object()
form = TagForm(request.POST)
if form.is_valid():
company.tags.add(form.cleaned_data['tag'])
return self.render_to_response(self.get_context_data())

django: data not save in db when using two models and two form in one template

I have difficulty saving my form into db. Every time I click on save it didn't save in db/admin. Can't seem to figure it out. I hope somebody out there can help me with this.
This project is about collecting information on a new customer for a construction company and if the customer exist in the db then it will view the detail of the particular customer and be able to edit the particular customer when needed and be able to overwrite the data when save. This information gather from a customer model and building model and customerForm and buildingForm and display in customer template.
models.py
class customer(models.Model)
F_NAME = models.CharField(max_length = 50)
L_NAME = models.CharField(max_length = 50)
ADD = models.CharField(max_length = 60, blank =True)
EMAIL = models.EmailField()
def __unicode__(self):
return '%s' % ( self.F_NAME )
class building(models.Model):
CUSTOMER = models.ForeignKey(customer)
B_USE = models.CharField(max_length = 2, blank = True, choices = c.Use)
B_FLOORSPACE = models.IntegerField(default=0)
B_YEAR = models.IntegerField(null = True, blank = True)
B_TYPE = models.CharField(max_length = 2, blank = True, choices = c.Type)
def __unicode__(self):
return '%s' % (self.B_USE)
forms.py
class customerForm(ModelForm):
F_NAME = forms.CharField(widget=forms.TextInput(attrs={'size':'34'}))
L_NAME = forms.CharField(widget=forms.TextInput(attrs={'size':'34'}))
EMAIL = forms.CharField(widget=forms.TextInput(attrs={'size':'19'}))
ADD = forms.CharField(widget=forms.TextInput(attrs={'size':'34'}))
class Meta:
model = customer
class buildingForm(ModelForm):
CUSTOMER = forms.CharField(widget=forms.TextInput(attrs={'size':'20'}))
B_FLOORSPACE = forms.CharField(widget=forms.TextInput(attrs={'size':'4'}))
B_YEAR = forms.CharField(widget=forms.TextInput(attrs={'size':'4'}))
class Meta:
model = building
exclude = ('CUSTOMER',)
widgets = {'B_USE' : RadioSelectNotNull(),
'B_TYPE' : RadioSelectNotNull(),
}
views.py
def customerView(request ,**kwargs ):
context ={}
try:
this_customer = customer.objects.get(id = kwargs ['pk'])
except:
this_customer = customer.objects.create(id = kwargs['pk'])
try:
bform = buildingForm(instance=building())
context['build']=True
context['bform']=bform
except:
context['build']=False
form = customerForm(instance=this_customer)
context['form']= form
if request.method == 'POST':
form = customerForm(request.POST, instance = customer())
bform = [buildingForm(request.POST, prefix = str(x), instance = building()) for x in range (0,3)]
if form.is_valid() and all ([bf.is_valid() for bf in bform]):
new_customer = form.save()
for bf in bform:
new_build = bf.save(commit = False)
new_build.CUSTOMER = new_customer
new_build.save()
return HttpResponseRedirect('customer.html')
else:
form = customerForm(instance=customer())
bform = [buildingForm(prefix=str(x), instance=building())for x in range(0,3)]
return render_to_response('customer.html',{'customer_form':form, 'build_form':bform}, context_instance = RequestContext(request))
customer.html
<form action="" method="post">
<button type="submit" name="customer">Save</button>
{% csrf_token %}
{{ form.id }}
...more code...
<table>
<tr><td><div>First Name</div>{{ form.F_NAME }}</td></tr>
<tr><td><div>Last Name</div>{{ form.L_NAME }}</td></tr>
</table>
....more code....
{% if build %}
...more code....
<table>
<tr><td><div>Build Use</div></td><td>{{ bform.B_USE }}</td>
<td><div>Build Space</div></td><td>{{ bform.B_FLOORSPACE }}</td>
</tr>
...more code...
</form>
I have try this demo on multiple model entry in single form
http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/
and
Django: multiple models in one template using forms
and
How to use two different Django Form at the same template?
but can't see where the mistake is. My task is quite simple for now, I just have to save all the information that has been keyed-in and saved in the database.
You probably have a validation error somewhere. Since you're not displaying any of the form errors in the template, your form will just be redisplayed with no explanation.

Set a non-null, but non-displayed django form field before form.save()

Am using django forms on my app. I have a model Client like this:
class Client(models.Model):
client_name = models.CharField(max_length=50)
email = models.EmailField(max_length=75)
password = models.CharField(max_length=128)
is_active = models.BooleanField()
last_login = models.DateTimeField(null=True)
class Meta:
db_table = u'client'
Then I have some other models 'Asset,AssetType` and then also specify a form for allowing a client to define their own assets - the asset types are created by the admin.
class AssetType(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table = u'assettype'
def __unicode__(self):
return self.name
class Asset(models.Model):
name = models.CharField(max_length=50)
type = models.ForeignKey(AssetType)
number = models.CharField(max_length=20)
client = models.ForeignKey(Client)
class Meta:
db_table = u'asset'
def __unicode__(self):
return self.name
class AssetForm(ModelForm):
class Meta:
model = Asset
Now, my problem is that when the Client is logged in, and the want to create a new Asset, the AssetForm, which I render like this, in the asset.html:
<FORM id="newasset_form" method="POST" action="/assets/">
{% csrf_token %}
<TABLE cellpadding="3" border="0" cellspacing="5">
<tr><th colspan="2">define a new asset</th></tr>
{{ form }}
<td align="center" colspan="2"><input type="submit" name="btn" id="btn" value="create asset" /></td>
</TABLE>
</FORM>
On the resultant form displayed to the Client, this setup displays the client field of the new Asset as a select with a drop-down of all existing clients, something I want to avoid. I want that client field to be auto-linked to the client whose session created the form - the currently logged in client, and not allow them to set the client to any other client. so how do i do this?
I had tried doing this, after the AssetForm is posted, to assign this client to the form's client field, then save, but it doesnt work!
if request.method == 'POST':
asset_form = AssetForm(request.POST)
if asset_form.is_valid():
asset_form.client = client
asset_form.save()
I want to define my form as :
class AssetForm(ModelForm):
class Meta:
model = Asset
exclude = ('client')
so that a client, can't tamper with the client field at all, when creating the new Asset.
class AssetForm(ModelForm):
class Meta:
model = Asset
exclude = ('client',) # don't forget that comma
Use the commit argument of the save method (docs):
if asset_form.is_valid():
instance = asset_form.save(commit=False)
instance.client = client
instance.save()
or create an instance of Asset where client is set and use that for the instance argument of creating your form:
def someview(request):
client = Client.objects.get(pk=<some_pk>)
asset = Asset(client=client)
if request.method == 'POST':
form = AssetForm(request.POST, instance=asset)
if form.is_valid():
form.save()
return HttpResponse('success')
else:
form = AssetForm(instance=asset)
context = {'form':form}
return render_to_response('some_template.html', context,
context_instance=RequestContext(request))