Python/Django Iterate ManyToMany Related Fields - python

I need some help with an issue.
I have three models, Reference, Relation ans Circuit. Relation is an inline of the first one. Circuit and Relation are related. What I have to do is:
- I'm in Reference 1 and I have selected some Circuits inside my Relation1 to RelationN.
- When I save, I need to save Relation1 to RelationN, and other RelationFirst (created when the Reference model is saved) who must contain all the Circuits that exist in the other Relations of that Reference.
The code that I have right now, who doesn't do it, is:
class Reference(models.Model):
title = models.CharField(max_length=200, verbose_name = _('title'))
def __unicode__(self):
return u"\n %s" %(self.title)
def save(self, force_insert=False, force_update=False, *args, **kwargs):
is_new = self.id is None
super(Reference, self).save(force_insert, force_update, *args, **kwargs)
if is_new:
Relation.objects.create(reference=self, first = True)
relation = Relation.objects.get(reference=self, first = True)
circuit = Circuit.objects.get(name = '0')
relation.circuit.add(circuit)
class Relation(models.Model):
first = models.BooleanField()
reference = models.ForeignKey(Reference)
circuit = models.ManyToManyField('Circuit', verbose_name = _('Circuits'), null=True, blank=True, related_name = 'relation_circuit')
def __unicode__(self):
return u"%s" %(self.reference)
def save(self, force_insert=False, force_update=False, *args, **kwargs):
relation1 = Relation.objects.get(reference=self.reference, first = True)
super(Relation, self).save(force_insert, force_update, *args, **kwargs)
for circ in self.circuits:
circuit = Circuit.objects.get(pk = circ)
relation1.circuit.add(circuit)
Any help? Because I can't iterate the ManyToManyRelatedField, and I don't know how to do it. Thank you very much!

You should do it that way:
for circ in self.circuit.all():

Related

django application with postgresql error value too long for type character varying(1)

I have a problem with django app and POSTGRESQL database with the slug field.
Error:
value too long for type character varying(1)
I test my app with sqlite database and everything works fine, but my app does not work in postgresql database. Any ideas why this is the case?
Test 1:
class MyModel(models.Model):
name = models.CharField(max_length=254)
slug_name = models.SlugField(max_length=254)
def save(self, *args, **kwargs):
self.slug_name = slugify(self.name)
super(MyModel, self).save(*args, **kwargs)
Test 2:
class MyModel(models.Model):
name = models.TextField(max_length=500)
slug_name = models.SlugField(max_length=500)
def save(self, *args, **kwargs):
self.slug_name = slugify(self.name)
super(MyModel, self).save(*args, **kwargs)
Test 3:
class MyModel(models.Model):
name = models.TextField()
slug_name = models.SlugField()
def save(self, *args, **kwargs):
self.slug_name = slugify(self.name)
super(MyModel, self).save(*args, **kwargs)
You're trying to insert a value with more that one character into a field specified as character varying(1). SQLite3 will allow this (see https://sqlite.org/datatype3.html) but PostgreSQL will give an error - i.e., it enforces that you have specified the maximum length as 1.

Django Rest Framework: Duplicate key value violates unique constraint

I have a problem with Django Rest Framework. This app I'm building is Avatar. User can update his/her own avatar, then avatar auto save with my path I defined (/users_id/photoset_id/filename.png). So I make function to save like this code:
def avatar_file_path(instance, filename):
ext = filename.split('.')[-1]
filename = '%s.%s' % (instance.id, ext)
return "users/%s/avatar/%s_%s" %(instance.user.id, instance.photoset.id, filename)
class Avatar(models.Model):
user = models.ForeignKey(User, related_name='avatar_set', null=True)
photoset = models.ForeignKey(PhotoSet, null=True, blank=True)
primary = models.BooleanField(default=True)
caption = models.TextField(blank=True, null=True)
image = models.ImageField(max_length=1024, upload_to=avatar_file_path)
is_public = models.BooleanField(_('is public'), default=True, help_text=_('Public photographs will be displayed in the default views.'))
date_uploaded = models.DateTimeField(default=datetime.datetime.now)
def save(self, force_insert=False, force_update=False, *args, **kwargs):
# Make one primary Avatar
if self.primary:
avatars = Avatar.objects.filter(user=self.user, primary=True).exclude(id=self.id)
avatars.update(primary=False)
# Set default photoset
if self.photoset is None:
if not PhotoSet.objects.filter(user=self.user, photoset_type=3).exists():
PhotoSet.objects.create(user=self.user, photoset_type=3, title='Profile Pictures')
self.photoset = PhotoSet.objects.get(user=self.user, photoset_type=3)
if PhotoSet.objects.filter(user=self.user, photoset_type=3).exists():
self.photoset = PhotoSet.objects.get(user=self.user, photoset_type=3)
# Model Save override
if self.id is None:
saved_image = self.image
self.image = None
super(Avatar, self).save(*args, **kwargs)
self.image = saved_image
super(Avatar, self).save(force_insert, force_update, *args, **kwargs)
When I create serializers POST with Django Rest Framework:
class AvatarCreateUpdateSerializer(ModelSerializer):
class Meta:
model = Avatar
fields = [
'user',
'image',
'caption',
'is_public',
]
It goes problem:
Error Log Tracking in line: super(Avatar, self).save(force_insert, force_update, *args, **kwargs)
Why I face with this problem and how can I fix this? Thank you in advance!
You are calling two times the save() method on the base class on your Model:
Here:
super(Avatar, self).save(*args, **kwargs)
And here:
super(Avatar, self).save(force_insert, force_update, *args, **kwargs)
As the comment below says, you should be using update_or_create or get_or_create to handle case like this.
Issue Fixed: Change super(Avatar, self).save(force_insert, force_update, *args, **kwargs) into super(Avatar, self).save(*args, **kwargs)
The problem is that the save function gets passed "forced_insert=True" by the rest framework. As you are saving twice with the same data, it is trying to force an insert of the same primary key twice.
A solution is that after the first save is to reset that forced_insert by
adding
kwargs['force_insert'] = False
before the second save. That will allow Django to use the update method, hence not try and create the same primary key twice.

Django ModelForm - Performance issue

I am using ModelForm to allow multiple rows edit at the same time. It is a very simple form that has series of yes_no columns. The model looks like:
models.py
class Yn(models.Model):
yn_id = models.IntegerField(primary_key=True)
description = models.CharField(max_length=30)
def __str__(self):
return ' '.join([
self.description,
])
class Meta:
managed = False
db_table = 'yn'
class Invoice(models.Model):
description = models.CharField(max_length=50)
invoice_date = models.DateTimeField()
...
invoice_sent_yn = models.ForeignKey('Yn', models.DO_NOTHING, db_column='invoice_sent_yn', related_name="invoice_sent_yn")
confirm_receipt_yn = models.ForeignKey('Yn', models.DO_NOTHING, db_column='confirm_receipt_yn', related_name="confirm_receipt_yn")
paid_yn = models.ForeignKey('Yn', models.DO_NOTHING, db_column='paid_yn', related_name="paid_yn")
forms.py
class InvoiceGridEdit(ModelForm):
model = Invoice
fields = ['description','invoice_date','invoice_sent_yn', 'confirm_receipt_yn', 'paid_yn']
def __init__(self, *args, **kwargs):
super(JurisGridEditForm, self).__init__(*args, **kwargs)
...
...
InvoiceFormSet = modelformset_factory(models.Invoice, form=InvoiceGridEdit)
views.py
class InvoiceUpdateGrid(CreateView):
template_name = "/invoice_update_grid.html"
model = Invoice
form_class = InvoviceViewEditForm
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return redirect("account_login")
def get(self, request, *args, *kwargs):
self.object = None
customer_number = self.request.GET.get('customer_number')
invoice_form = InvoiceFormSet(queryset=Invoice.objects.filter(customer_number = customer_number)
return self.render_to_response(self.get_context_data(invoice_form=invoice_form))
def post(self, request, *args, **kwargs):
self.object = None
invoice_form = InvoiceFormSet(self.request.POST)
if (invoice_form.is_valid()):
return self.form_valid(invoice_form)
else:
return self.form_invalid(invoice_form)
def form_valid(self, invoice_form):
...
...
invoice_form.save()
return redirect("customer_list")
def form_invalid(self, invoice_form):
return self.render_to_response(self.get_context_data(invoice_form=invoice_form))
The forms works fine, get and post works, except, it takes a while (~30 sec) to retrieve and update. Using django-debug-toolbar, it looks like the yn columns retrieve separately for each column for each row (~2k rows). The Yn table only has 3 rows -1 - Unknown, 0 - No, 1 - Yes.
I tried to search for work around to stop the craziness of Django hitting the DB 900 times per retrieval. I found something about caching but I have no idea how to do it.
Thanks in advance.

Building tags plugin for django-wiki using django-taggit. Cannot save with .save_m2m() - type object has no attribute 'save_m2m'

I am building a custom tags plugin for django-wiki using django-taggit to save tags. I cannot save the form with .save_m2m as it says in the django-taggit docs. The tags can be saved in the admin but not through the fronted form because I cant save with .save_m2m(). I get the following error even after the form has been saved. Any help would be appreciated.
type object 'SidebarForm' has no attribute 'save_m2m'
wiki_plugins.py
class TagPlugin(BasePlugin):
slug = settings.SLUG
sidebar = {
'headline': _('Tags'),
'icon_class': 'fa-picture-o',
'template': 'sidebar.html',
'form_class': forms.SidebarForm,
'get_form_kwargs': (lambda a: {'instance': models.Tag(article=a)})
}
models.py
class TagRevision(RevisionPluginRevision):
def can_write(self, user):
if not settings.ANONYMOUS and (not user or user.is_anonymous()):
return False
return RevisionPlugin.can_write(self, user)
def can_delete(self, user):
return self.can_write(user)
class Meta:
verbose_name = _('tag')
verbose_name_plural = _('tags')
db_table = 'wiki__plugins_tags_tag' # Matches label of upcoming 0.1 release
if settings.APP_LABEL:
app_label = settings.APP_LABEL
def __str__(self):
if self.current_revision:
return ugettext('Tag: %s') % self.current_revision.tagrevision
else:
return ugettext('Current revision not set!!')
#python_2_unicode_compatible
class TagRevision(RevisionPluginRevision):
tags = TaggableManager()
def inherit_predecessor(self, tag):
"""
Inherit certain properties from predecessor because it's very
convenient. Remember to always call this method before
setting properties :)"""
predecessor = tag.current_revision.tagrevision
self.plugin = predecessor.plugin
self.deleted = predecessor.deleted
self.locked = predecessor.locked
self.tag = predecessor.tag
if not skip_image_file:
try:
self.tags = predecessor.tags
except IOError:
self.tags = None
class Meta:
verbose_name = _('tag revision')
verbose_name_plural = _('tag revisions')
# Matches label of upcoming 0.1 release
db_table = 'wiki_plugins_tags_tagrevision'
if settings.APP_LABEL:
app_label = settings.APP_LABEL
ordering = ('-created',)
def __str__(self):
return ugettext('Tag Revsion: %d') % self.revision_number
forms.py
from wiki_plugins_tags import models
class SidebarForm(PluginSidebarFormMixin):
def __init__(self, article, request, *args, **kwargs):
self.article = article
self.request = request
super(SidebarForm, self).__init__(*args, **kwargs)
self.fields['tags'].required = True
def save(self, *args, **kwargs):
if not self.instance.id:
tagged = models.Tag()
tagged.article = self.article
kwargs['commit'] = False
revision = super(SidebarForm, self).save(*args, **kwargs)
revision.set_from_request(self.request)
tagged.add_revision(self.instance, save=True)
return revision
return super(SidebarForm, self).save(*args, **kwargs)
class Meta:
model = models.TagRevision
fields = ('tags',)
class RevisionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.tags = kwargs.pop('tags')
self.request = kwargs.pop('request')
super(RevisionForm, self).__init__(*args, **kwargs)
self.fields['tags'].required = True
def save(self, *args, **kwargs):
if not self.instance.id:
kwargs['commit'] = False
revision = super(RevisionForm, self).save(*args, **kwargs)
revision.inherit_predecessor(self.tags, skip_image_file=True)
revision.deleted = False # Restore automatically if deleted
revision.set_from_request(self.request)
self.tags.add_revision(self.instance, save=True)
return revision
return super(RevisionForm, self).save(*args, **kwargs)
class Meta:
model = models.TagRevision
fields = ('tags',)

django forms with ModelChoiceField

After researching for days I'm still confused with creating a form involving 4 tables which are all connected via ForiegnKey. I'm not even sure if I'm using the right approach.
Should I use forms.Form or ModelForm? What I'm looking for I'm sure is common but all of my attempts are in vain. It seems like I'm making this more complicated than it should be since all 4 tables are related.
To the Point: To create a workorder, pick a Building, then pick a Unit within that Building, then pick a caller from Tenant(s) within that Unit. Then gather all data in view and save WorkOrder.
Using Django 1.6
# models.py
class Building(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=200)
...
def __unicode__(self):
return self.name
class Unit(models.Model):
name = models.ForeignKey(Building)
unit = models.CharField(max_length=30)
...
def __unicode__(self):
return self.unit
class Tenant(models.Model):
unit = models.ForeignKey(Unit)
name = models.ForeignKey(Building)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
...
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
class WorkOrder(models.Model):
name = models.ForeignKey(Building)
unit = models.ForeignKey(Unit)
ordernum = models.AutoField(primary_key=True)
...
def __unicode__(self):
return self.unit
forms.py
# forms.py
class WorkOrderForm(forms.Form):
building_choice = forms.ModelChoiceField(queryset=Building.objects.all(),
empty_label='Pick a building',
)
def __init__(self, *args, **kwargs):
super(WorkOrderForm, self).__init__(*args, **kwargs)
self.fields['building_choice'].label = 'Building'
unit_choice = forms.ModelChoiceField(queryset=Unit.objects.(????),
empty_label='Pick a unit',
)
def __init__(self, *args, **kwargs):
super(WorkOrderForm, self).__init__(*args, **kwargs)
self.fields['unit_choice'].label = 'Unit'
caller_choice = forms.ModelChoiceField(queryset=Tenant.objects.(????),
empty_label='Who called',
)
def __init__(self, *args, **kwargs):
super(WorkOrderForm, self).__init__(*args, **kwargs)
self.fields['caller_choice'].label = 'Tenant'
views.py (incomplete)
#views.py
def create(request):
if request.method == 'POST':
form = WorkOrderForm(request.POST)
if form.is_valid():
workorder = WorkOrder(name=form.cleaned_data['name'],
unit=form.cleaned_data['unit'],
call_date=form.cleaned_data['call_date'],
caller=form.cleaned_data['caller'],
problem_desc=form.cleaned_data['problem_desc'])
workorder.save()
return HttpResponseRedirect('/workorder/')
else:
form = WorkOrderForm()
return render(request, 'workorder_form.html', {'form': form})
If someone could let me know the correct way to go about this I'd be forever grateful.
It's been a while since I posted this question but I found a django package django-clever-selects that met my needs. The docs and example project were well commented. Thanks to all that helped mr earlier.

Categories