I need have a search box, one of fields of the model has a M2M field. I got to put it works but only works when i look for the id of the M2M field, not for the name. my models:
class Specialities(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Profile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(max_length=200)
specialities = models.ManyToManyField(Specialities)
def __str__(self):
return self.name
And my view:
class SearchView(TemplateView):
template_name = 'contadores/search.html'
def post(self,request,*args,**kwargs):
buscar = request.POST['buscar']
contadores = Profile.objects.filter(specialities=buscar)
ctx = {'contadores':contadores}
return render_to_response('contadores/resultados.html',ctx,context_instance=RequestContext(request))
The queryset in "contadores" works fine, but as i told before, the search box only receive the id of the M2M field, if i look for the word in the search box django says: invalid literal for int() with base 10: 'niif' I know the reason, but how can i pass to the search box the word of the M2M field associated to the Specialities model instead the id?
What you can do is search by related table, like this:
contadores = Profile.objects.filter(specialities__name__iexact = request.POST['buscar'])
Try like this:
buscar = Specialities.objects.filter(name__iexact = request.POST['buscar'])
if buscar.exists():
contadores = Profile.objects.filter(specialities=buscar[0])
Related
I have the following Models:
class Book(models.Model):
name = models.CharField(max_length=128)
isbn = models.CharField(max_length=13, unique=True)
available = models.BooleanField(default=True)
class Borrow(models.Model):
date = models.DateTimeField(auto_now_add=True)
book = models.ForeignKey(Book)
and the following ModelForm:
class CreateBorrowForm(forms.ModelForm):
class Meta:
model = Borrow
fields = ['book']
def clean_book(self):
book = self.cleaned_data['book']
try:
return Book.objects.get(id=book, available=True)
except Book.DoesNotExist:
raise ValidationError('Book does not exist or it is unavailable')
I would like to have a form that expects the isbn field of the Book model, instead of id. As the isbn field is unique, it does make sense. In the clean_book method I would need to do a little change to have the following line:
return Book.objects.get(isbn=book, available=True)
The problem is that I cannot find an approach to force the form to use a different unique identifier. In my specific case, this is required to avoid brute force enumerating over numerical IDs.
You'd need to use a custom field for that, and override the save() method instead of the clean__field():
class CreateBorrowForm(forms.ModelForm):
book_isbn = forms.CharField()
class Meta:
model = Borrow
fields = ['book_isbn']
def save(self, commit=True):
instance = super().save(commit=False)
book_isbn = self.cleaned_data['book_isbn']
try:
book = Book.objects.get(isbn=book_isbn, available=True)
instance.book = book
except Book.DoesNotExist:
raise ValidationError('Book does not exist or it is unavailable')
if commit:
instance.save()
return instance
I have the following (simplified) data model:
class Article(Model):
uuid = models.CharField(primary_key=True, max_length=128)
class Attribute(Model):
uuid = models.CharField(primary_key=True, max_length=128)
article = models.ForeignKey(Article, related_name='attributes')
type = models.CharField(max_length=256)
value = models.CharField(max_length=256)
An example usage would be an article with an attribute attached to it with type="brand" and value="Nike". Now I want to write an API which can get all articles with a certain brand, but I can't seem to write the filter for it. This is what I have so far:
class PhotobookFilter(df.FilterSet):
brand = df.CharFilter(method='filter_brand')
class Meta:
model = Article
def filter_brand(self, queryset, name, value):
return queryset.filter('order__attributes')
class PhotobookViewSet(AbstractOrderWriterViewSet):
queryset = Article.objects.all()
serializer_class = ArticlePhotobookSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = PhotobookFilter
The line with queryset.filter is obviously not correct yet. I need to create a filter here that returns all articles that contain an attribute with type="brand" and value=value. How would I do this?
Are you sure you want to condense both lookups (type and value of Attribute) into one filter? Why not allow filtering on both fields separately?
E.g.
class PhotobookFilter(df.FilterSet):
type = df.CharFilter(method='filter_type')
value = df.CharFilter(method='filter_value')
class Meta:
model = Article
def filter_type(self, queryset, name, value):
return queryset.filter(**{'attributes__type': value})
def filter_value(self, queryset, name, value):
return queryset.filter(**{'attributes__value': value})
And now a query like ?type=brand&value=Nike should work.
Obviously you could condense both conditions into one filter and for example hard code the band part:
class PhotobookFilter(df.FilterSet):
brand = df.CharFilter(method='filter_brand')
def filter_brand(self, queryset, name, value):
return queryset.filter(**{'attributes__type': 'brand', 'attributes__value': value})
But keeping them separate feels way more flexible.
You could also filter in reverse like this:
class PhotobookFilter(df.FilterSet):
brand = df.CharFilter(method='filter_brand')
class Meta:
model = Article
def filter_brand(self, queryset, name, value):
articles = Attribute.objects.filter(type="brand", value=value).values_list('article_id', flat=True)
return queryset.filter(id__in=articles)
This will create subquery for Attribute, which will still be one sql request in the end
Use search_fields .For correct result rename your 'type' attribute name http://www.codesend.com/view/09ca65d42248fe1d89d07ce151f4f050/
I am trying to limit the fields to in my table. The only way I see to do it is through the PersonTable object with the field property like this fields = [first_name, last_name]. I want to do it from a request form. I tried to override the get_queryset() method but it did not work only passed in less data but the columns were still there just blank. Is there a good way to do it with the generic view?
class Person(models.Model):
first_name =models.CharField(max_length=200)
last_name =models.CharField(max_length=200)
user = models.ForeignKey("auth.User") dob = models.DateField()
class PersonTable(tables.Table):
class Meta:
model = Person
fields = [first_name, last_name]
class PersonList(SingleTableView):
model = Person
table_class = PersonTable
If anyone runs into this same issue, there is an exclude instance variable on the table class so you can just override get_table and do something like this in your view:
class PersonList(SingleTableView):
model = Person
table_class = PersonTable
template_name = "person.html"
def get_table(self):
table = super(PersonList, self).get_table()
columns = self.request.GET.getlist('column')
tuple_to_exclude = tuple(set(table.columns.names()) - set(columns))
table.exclude = tuple_to_exclude
return table
models.py:
import datetime
from django.db import models
from pygments.lexers import get_all_lexers
LEXERS = [item for item in get_all_lexers() if item[1]]
class Classname(models.Model):
class_name = models.CharField(max_length=8)
def __str__(self):
return self.class_name
class Sectionname(models.Model):
class_name = models.ForeignKey(Classname)
section_name = models.CharField(max_length=1, default='A')
def __str__(self):
return self.section_name
class Teachername(models.Model):
field = """ I want to define here a foreign key field(inherited from Sectionname model)which saves the primary key value of row corresponding to two fields (class_name, section_name) above."""
teachname = models.CharField(max_length=50, verbose_name='teacher Name')
def __str__(self):
return self.teachname
class Attendancename(models.Model):
teacher_name = models.ForeignKey(Teachername)
date = models.DateField('Date')
intime = models.TimeField('IN-TIME')
outtime = models.TimeField('OUT-TIME')
def hours_conversion(self):
tdelta = (datetime.datetime.combine(datetime.date.today(),self.outtime) - datetime.datetime.combine(datetime.date.today(),self.intime))
hours, minutes = tdelta.seconds//3600, (tdelta.seconds//60)%60
return '{0}hrs {1}mins'.format(hours, minutes)
def __str__(self):
return "%s" %self.teacher_name
forms.py:
from django import forms
from django.forms import ModelForm
from .models import Classname, Sectionname, Teachername, Attendancename
class ClassnameForm(ModelForm):
class_name = forms.CharField(max_length=8)
class Meta:
model = Classname
fields = ('class_name',)
class SectionnameForm(ModelForm):
class_name = forms.ModelChoiceField(queryset=Classname.objects.all())
class Meta:
model = Sectionname
fields = ('section_name', 'class_name',)
class TeachernameForm(ModelForm):
field = """ Here I also want to do the same thing, I tried to make a form field, which shows value of both 'section_name' and 'class_name' from above model but only saves the value of corresponding row's primary key."""
class Meta:
model = Teachername
fields = ('classname', 'secname', 'teachname',)
class AttendancenameForm(ModelForm):
teacher_name = forms.ModelChoiceField(queryset=Teachername.objects.all())
class Meta:
model = Attendancename
fields = ('teacher_name', 'date', 'intime', 'outtime',)
I'm trying to save the 'pk' value of Sectionname model fields('calss_name', 'section_name') into Terachername model's single 'field', I also want to show the both the values to user using form field 'field', but behined the scenes only primary key values needs to be saved.
Is it possible to do so? If it is then how can I implement it in my app?
Please! provide your suggestions....
Thanks! in advance.....
You cannot store two foreign keys to two different tables in a single models.ForeignKey field, and it really wouldn't make any sense (if the reason is not obvious to you then you should learn more about relational model).
But anyway: since a Sectionname belongs to one single Classname, you don't need anything else than the Sectionname pk to get the related Classname:
class Teachername(models.Model):
sectionname = models.ForeignKey(Sectionname)
teachname = models.CharField(max_length=50, verbose_name='teacher Name')
def __str__(self):
return self.teachname
teacher = Teachername.objects.get(pk=XXX)
print teacher, teacher.sectionname, teacher.sectionname.classname
Or if a teacher is supposed to teach more than one section:
class Teachername(models.Model):
sectionnames = models.ManyToMany(Sectionname)
teachname = models.CharField(max_length=50, verbose_name='teacher Name')
def __str__(self):
return self.teachname
teacher = Teachername.objects.get(pk=XXX)
for sectionname in teacher.sectionnames.all():
print teacher, sectionname.classname
Strange error. When I am trying to add some data to my charfield it shows me error like this: invalid literal for int() with base 10:
Here is my models:
class Follower(models.Model):
follower = models.CharField(max_length=140)
def __unicode__(self):
return self.follower
class Following(models.Model):
following = models.CharField(max_length=140)
def __unicode__(self):
return self.following
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField()
followers = models.ManyToManyField(Follower)
following = models.ManyToManyField(Following)
Views:
if request.GET.get('follow'):
author = UserProfile.objects.get(user__username__iexact=username)
b = "AAA"
author.followers.add(b)
What to do?
followers is not a CharField, it is a ManyToManyField. You can't just add text to it: you need to create an instance of Follower, or get an existing one, and add it.