How to capture many to many field values via get_initial command - python-3.x

I am slowly progressing in my django journey, but this one has me stumped. I am trying to populate a CreateView with a different model via a copy command using the get_initial override. All of the attributes copy as I would expect with the exception of the ManytoMany fields. I've researched this topic most of today, and found the following which is very close to what I'm trying to figure out KeyError: 'manager' in django get_initial.
My View...
class BookView(LoginRequiredMixin,CreateView):
model = Book
template_name = 'book/titles.html'
form_class = BookForm
def get_initial(self):
initial = super(BookView, self).get_initial()
author = author.objects.get(pk=self.kwargs["pk"])
initial = author.__dict__.copy()
initial.update({
"author": author.name,
}}
for field in self.form_class.base_fields.items():
value = getattr(self.get_object(), field)
if field == 'author':
value = self.get_object().author.all()
initial.update({field: value})
return initial
I incorporated the suggested change based on the issue that I found on SO, but I still am getting a 'manager" KeyError. I am ultimately trying to populate the manytomanyfield in my model and then save the values, but to no avail. Any suggests are appreciated!

What a difference a day makes....
def get_initial(self):
initial = super(BookView, self).get_initial()
author = author.objects.get(pk=self.kwargs["pk"])
initial = author.__dict__.copy()
initial.update({
"author": author.name.all(),
}}
return initial
I added a .all() after the reference to the manytomanyfield in my initial get and also update the form to get the field in question. Much cleaner than a few hacks I kinda got working along the way.

Related

Correct way to define the initial value of a form field in Django from a database, when database values may change

I am trying to create an interview feedback capture app using Django. The interview feedbacks follow a template. The template would evolve with time. Therefore whenever a new interview feedback template is available, it is updated to the database by an admin user.
Whenever an interviewer opens the app, he should see the latest value of the template available in the database as the initial value of the feedback form.
Currently I am able to provide the initial value of the feedback field using the 'initial' argument of the feedback field.
Below is the code (I am interested in the R1Form):
from django import forms
from .models import R1
from .model_templates import template_R1
from ckeditor.widgets import CKEditorWidget
class DateInput(forms.DateInput):
input_type = 'date'
class R1Form(forms.ModelForm):
interview_date = forms.DateField(widget = DateInput())
feedback = forms.CharField(widget = CKEditorWidget(), initial = template_R1.objects.all().last().template)
class Meta:
model = R1
fields = ['interview_date', 'interviewers', 'comment', 'recommended_level', 'progress']
The problem with this approach if that if the template is updated the form field still shows an earlier snapshot of the template when the django server was started.
Is there any other way the form field would show dynamic values as soon as the template is updated in the database? I believe somehow if the initial value could be passed from the views.py, then this could be resolved?
Okay so, I found an elegant solution.
I used the init method of the form class to initialize the feedback field:
class R1Form(forms.ModelForm):
interview_date = forms.DateField(widget=DateInput())
feedback = forms.CharField(widget=CKEditorWidget())
class Meta:
model = R1
fields = ['interview_date', 'interviewers', 'feedback', 'comment', 'recommended_level', 'progress']
And from the views, I used the get_initial method to pass the initial value of the form as the template value from the database.
class R1CreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = R1
template_name = "interviews/r1/create.html"
def get_initial(self):
"""Return the initial data to use for forms on this view."""
return {'feedback': template_R1.objects.all().last().template}

Django Rest Framework: Why does PrimaryKeyRelatedField document as a string in the schema when read_only?

I have a serializer with a PrimaryKeyRelatedField:
field_name = serializers.PrimaryKeyRelatedField(queryset=ModelClass.objects.all(), read_only=False)
With this setup, the Schema properly identifies the parameter as an integer (the PK). But, when I change to:
field_name = serializers.PrimaryKeyRelatedField(read_only=True)
(it will not let you specify queryset and read_only at the same time) then the parameter is identified as a string in the Schema.
Why would this be? Is this correct/expected behavior or perhaps a bug?
Well, I had banged my head on this one long enough to post on SO, but as I've continued to dig into it I think I am making some progress.
At rest_framework/schemas/openapi.py:380 inside of map_field() you find the following:
if isinstance(field, serializers.PrimaryKeyRelatedField):
model = getattr(field.queryset, 'model', None)
if model is not None:
model_field = model._meta.pk
if isinstance(model_field, models.AutoField):
return {'type': 'integer'}
RelatedField won't let you specify a queryset when read_only=True though, so then the "model" in the above code snippet is always None when read_only=True, and you end up getting type="string" at the bottom of the map_field function.
So this explains why it is currently happening, and seems like a bug in DRF, but now I guess I just need to look into what the appropriate fix would be.
I've opened up a corresponding issue against DRF: https://github.com/encode/django-rest-framework/issues/7427

Django Queryset Values of Children and Parent

I am looking for a way to retrieve a parent field during a query of the the children records. At this time I have the following example model.
class Record(models.Model):
event_title=models.CharField(max_length=500)
event_description=models.CharField(max_length=4000)
class SecondTable(models.Model):
event_code=models.ForeignKey(Record, default=0, on_delete=models.CASCADE)
wasfun=models.BoolField(default=True)
When I view the values of the queryset and select_related below, the values from the parent don't seem to be included (i.e. event_description). However, the .query property shows all the fields being selected.
SecondTable.objects.all().select_related("event_code").values()
Is there a way to see all values from the joined tables? Sorry for a newbie question. Thanks!
I think not in only one line, but you can try with next:
values_second_table = [s.name for s in SecondTable._meta.fields]
values_first_table = ['event_code__{}'.format(r.name) for r in Record._meta.fields]
my_values = values_second_table + values_first_table
SecondTable.objects.all().select_related("event_code").values(*my_values)

adding reserved lot name in sale.order.line in odoov10

I would like to write small module that inherit sale.order.line and adding reserved lot on sale order line tree view.
under the sale.order.line module, there is the field name move_ids (stock.move , one2many) fields. I would like to create move_ids.move_line_ids.lot_id
So I tried the following code:
lot_name = fields.Char(related="move_ids.move_line_ids.lot_id", string="String")
but no luck and saw internal server error.
jooze
You can not do that, type of related field lot_name is inconsistent with lot_id.
Try to use a computed Many2many field to get all lot ids related to the current record.
Edit:
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
lot_ids = fields.Many2many('stock.production.lot', compute='_get_lot_ids')
#api.one
#api.depends('move_ids.move_line_ids.lot_id')
def _get_lot_ids(self):
# returns the union of all lots, with duplicates removed
self.lot_ids = self.mapped('move_ids.move_line_ids.lot_id')

Flask-AppBuilder equivalent of SQLite WHERE clause to filter column data

I'm new to Flask and have started designing a front end for an inventory management database using Flask-AppBuilder.
I have created several models and have have managed to display my sqlite data in tables using Flask-AppBuilder's views.
However, I don't seem to be able to find the equivalent of SQLite WHERE clause to filter or "restrict" column data. I've been reading a lot about sqlalchemy, filters, queries but this has left me more confused that anything else and the explanations seem to be extremely elaborate and complicated to do something which is extremely simple.
Assuming we reproduce the following SQLite query in Flask-AppBuilder:
SELECT Field_A
FROM Table_A
WHERE Field_A = 'some text'
with:
result = session.query(Table_A).filter_by(Field_A = 'some text').all()
Where does the above line of code go in my app?
Considering I have the following Class:
class Table_A(Model):
id = Column(Integer, primary_key=True)
Field_A = Column(String)
def __repr__(self):
return self
and View:
class Table_AView(ModelView):
datamodel = SQLAInterface(Table_AView)
label_columns = {'Field_A':'A'}
list_columns = ['Field_A']
After much digging flask-appbuilder uses it's own filterclass in order to enable you to filter your views.
All the classes are referenced here on GitHub:
Flask Filter Clases List
Also not the difference between FilterEqual and FilterEqualFunction here:
What is the difference between : FilterEqual and FilterEqualFunction?
For other customisation and first port of call of Flask-appbuilder go straight to the API Reference where you'll find a couple of examples of the filterclass in action.
In essence it is extremely simple. In your views.py code within the ModelView class you want to filter simply add base_filters = [['field_A', FilterEqual, 'abc']] like so:
`class Table_AView(ModelView):
datamodel = SQLAInterface(Table_AView)
label_columns = {'Field_A':'A'}
list_columns = ['Field_A']
base_filters = [['field_A', FilterEqual, 'abc']]`
This will only show the lines where the field_A variable is equal to abc.
Hope this helps someone as it took me nearly (sigh) two weeks to figure it out...
SQLALchemy is an ORM (Object-Relational Mapping), it mean that you dont have to deal with raw SQL, you will call a function that you "build" (by adding filters in your case). It will transparently generate an SQL query, execute it, and return the result as python objects.
I would suggest you to read closely at sqlalchemy documentation about filters again, especially filter_by :
http://docs.sqlalchemy.org/en/latest/orm/query.html#sqlalchemy.orm.query.Query.filter_by
It is the easiest way to apply a WHERE with sqlalchemy.
If you have declared correctly the model for Table_A, you should be able to use it so:
result = session.query(Table_A).filter_by(Field_A = 'some text').all()
Here session.query(Table_A).filter_by(Field_A = 'some text') will generate the SQL, and .all() will execute it.

Resources