How to correctly write a condition in view Django? - django

The meaning of the program is to select analogues from the list and link them. I bind all values.
I think the problem is in the wrong if. How to fix it
My view:
def editpart(request, id, **kwargs):
if request.method == 'POST':
part.name = request.POST.get("name")
part.description = request.POST.get("description")
analogs = Part.objects.all()
for analog_zap in analogs:
analog = analog_zap.analog
if Part.objects.filter(analog_analog = analog):
part.analog.add(analog_zap.id)
My model:
class Part(models.Model):
name = models.CharField('Название', max_length=100)
analog = models.ManyToManyField('self', blank=True, related_name='AnalogParts')

I'm just going to assume you have gotten a part object before trying to assign the following:
part.name = request.POST.get("name")
part.description = request.POST.get("description")
Whether this was intended to update the "retrieved part object" or not, I'd recommend that you have instead two fresh variables to collect the info from the post request, then update the part object with these if any related info were found in the database.
name = request.POST.get("name")
description = request.POST.get("description")
As for the real issue here... Not sure I'm understanding your question much but I do see a problem with one of your if statements though. You have:
for analog_zap in analogs:
analog = analog_zap.analog
if Part.objects.filter(analog_analog = analog): # problem here...
part.analog.add(analog_zap.id)
As you've posted:
class Part(models.Model):
name = models.CharField('Название', max_length=100)
analog = models.ManyToManyField('self', blank=True, related_name='AnalogParts') # right here...
The Part model has a field called analog, not analog_analog: maybe you meant analog__analog. But maybe you should try checking by: if Part.objects.filter(analog__pk=analog.pk) or if Part.objects.filter(analog__in=[analog]).distinct().
Furthermore, what you might want to do is to check if something exists, so add .exists() to the end of if Part.objects.filter(analog__pk=analog.pk). Example:
if Part.objects.filter(analog__pk=analog.pk).exists():
...
Looking like:
for analog_zap in analogs:
analog = analog_zap.analog
if Part.objects.filter(analog__pk=analog.pk).exists():
part.analog.add(analog_zap.id)
# update the name and description here as well with the values retrieved from the post request
part.name = name
part.description = description
You could try that.
UPDATES
What worked in this context is:
Part.objects.filter(analog__in=[analog_zap]).distinct()

Related

Prepare a string representation of a command and then execute id

Django==2.2.2
Now I have this code:
Model
class YandexResponse(models.Model):
time = models.DateTimeField(auto_now=True)
campaigns = models.TextField()
ad_groups = models.TextField()
ads = models.TextField()
keywords = models.TextField()
sitelinks = models.TextField()
View
yandex_response_record, created = YandexResponse.objects.get_or_create(id=1)
if what_to_update == "campaigns":
yandex_response_record.campaigns=json.dumps(data)
yandex_response_record.save()
elif what_to_update == "ad_groups":
yandex_response_record.ad_groups=json.dumps(data)
yandex_response_record.save()
...
I'd like to have something like:
tmp = "yandex_response_record.{}=json.dumps(data)".format(what_to_update)
execute(tmp);
yandex_response_record.save()
Could you tell me whether is is somehow possible? If it is not possible, could you suggest me some elegant solution here?
For this you can use the setattr function as specified in the docs.
'setattr' is the counterpart of getattr(). The arguments are an object, a string and an arbitrary value. The string may name an existing attribute or a new attribute.
So instead of checking for the value of the field passed, you can do:
yandex_response_record, created = YandexResponse.objects.get_or_create(id=1)
setattr(yandex_response_record, what_to_update, json.dumps(data))
yandex_response_record.save()
What it does is updates the field name specified in what_to_update as provided in json.dumps(data).
Maybe it will be helpful to you.
You are looking for the built-in setattr function.
setattr(yandex_response_record, what_to_update, json.dumps(data))
yandex_response_record.save()

Is it possible to add a variable to Django Model Field.choices?

Is it possible to add a variable to Django Model Field.choices?
I lose functionality when I have to add it statically.
IP_CHOICES = (
('192.168.1.0', '192.168.1.0'),
)
ip_address = models.IPAddressField(choices=IP_CHOICES, unique=True, blank=True)
I use a Python IP Interpreter called IPy, to calculate the correct IP block.
ip = IP(self.network + slash)
for rangeip in enumerate(ip[2:-1]):
IP_CHOICES = (
("%s" %rangeip, "%s" %rangeip)
)
Is this possible? If so, please help. Been trying to hack it for the past week and got no where. Any help is appreciated.
Please view Model Class.
#IP Block Class
class IP_block(models.Model):
network = models.IPAddressField(unique=True)
slash = models.ForeignKey(Subnet, verbose_name='CIDR')
subnet = models.CharField(max_length=64, blank=True)
gateway_ip = models.CharField(max_length=64, blank=True)
broadcast_ip = models.CharField(max_length=64, blank=True)
ip_range = models.TextField(blank=True, verbose_name='Available IP Range')
dslam = models.ManyToManyField(Dslam, verbose_name='Dslam', blank=True)
#ip block and range save function
def save(self, *args, **kwargs):
slash = unicode(self.slash)
broadcast = IP(self.network + slash).broadcast()
subnet = IP(self.network+slash).strNetmask()
self.broadcast_ip = broadcast
self.subnet = subnet
ip = IP(self.network + slash)
for gateway in ip[1]:
self.gateway_ip = gateway
#rangeip for loop
ip = IP(self.network + slash)
if self.ip_range:
print 'no override'
else:
for rangeip in ip[2:-1]:
self.ip_range += "%s\n" %rangeip
IP_CHOICE = "(%s" %rangeip + ", %s)," %rangeip
#ip_list select
ip_list = models.CharField(choices=IP_CHOICE, max_length=128, blank=True)
super(IP_block, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = 'IP Blocks'
def __unicode__(self):
return self.network
You have many fairly basic errors here. For example, in your suggested syntax:
for rangeip in enumerate(whatever):
IP_CHOICES = (do_something)
It should be obvious to you that you are simply overwriting IP_CHOICES each time through the loop. At the end of the loop, it will simply have the value of the last iteration, which isn't by itself in a suitable format for choices.
You have this same pattern a number of times. Please think about what it is actually doing.
But there's an even worse error in your save function, where you have this line:
ip_list = models.CharField(choices=IP_CHOICE, max_length=128, blank=True)
I have absolutely no idea what you think that is doing. You can't define a field in the middle of a save method. You can set a field's value, but you can't suddenly define a new field (again, please think about it: how would that work with the database? And remember fields are class-level attributes: all instances of that model need to have the same field selection).
It's almost impossible to understand what you are actually trying to do. I think you are trying to provide a choice of IP addresses for one field in the model (ip_list), once the user has set the range in another field (ip_range). (It would have been useful if you'd stated that explicitly up front.)
The place to do this is in the form, not in the model. Setting choices on a model field is really just a shortcut to setting them on forms automatically created from that model, but if you need to do something dynamic you need to define the form yourself and put the logic there. I guess it would be something like this:
class IPBlockForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(IPForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.ip_range:
ip_list_choices = get_ip_list_from_wherever(self.instance_ip_range)
self.fields['ip_list'] = forms.ChoiceField(choices=ip_list_choices)
class Meta:
model = IP_block
But naturally you need to fix the other logic errors in your save method, which I mention above, first.

Django difficulty saving multiple model objects within save method

This is a hard question for me to describe, but I will do my best here.
I have a model that is for a calendar event:
class Event(models.Model):
account = models.ForeignKey(Account, related_name="event_account")
location = models.ForeignKey(Location, related_name="event_location")
patient = models.ManyToManyField(Patient)
datetime_start = models.DateTimeField()
datetime_end = models.DateTimeField()
last_update = models.DateTimeField(auto_now=False, auto_now_add=False, null=True, blank=True)
event_series = models.ForeignKey(EventSeries, related_name="event_series", null=True, blank=True)
is_original_event = models.BooleanField(default=True)
When this is saved I am overriding the save() method to check and see if the event_series (recurring events) is set. If it is, then I need to iteratively create another event object for each recurring date.
The following seems to work, though it may not be the best approach:
def save(self, *args, **kwargs):
if self.pk is None:
if self.event_series is not None and self.is_original_event is True :
recurrence_rules = EventSeries.objects.get(pk=self.event_series.pk)
rr_freq = DAILY
if recurrence_rules.frequency == "DAILY":
rr_freq = DAILY
elif recurrence_rules.frequency == "WEEKLY":
rr_freq = WEEKLY
elif recurrence_rules.frequency == "MONTHLY":
rr_freq = MONTHLY
elif recurrence_rules.frequency == "YEARLY":
rr_freq = YEARLY
rlist = list(rrule(rr_freq, count=recurrence_rules.recurrences, dtstart=self.datetime_start))
for revent in rlist:
evnt = Event.objects.create(account = self.account, location = self.location, datetime_start = revent, datetime_end = revent, is_original_event = False, event_series = self.event_series)
super(Event, evnt).save(*args, **kwargs)
super(Event, self).save(*args, **kwargs)
However, the real problem I am finding is that using this methodology and saving from the Admin forms, it is creating the recurring events, but if I try to get self.patient which is a M2M field, I keep getting this error:
'Event' instance needs to have a primary key value before a many-to-many relationship can be used
My main question is about this m2m error, but also if you have any feedback on the nested saving for recurring events, that would be great as well.
Thanks much!
If the code trying to access self.patient is in the save method and happens before the instance has been saved then it's clearly the expected behaviour. Remember that Model objects are just a thin (well...) wrapper over a SQL database... Also, even if you first save your new instance then try to access self.patient from the save method you'll still have an empty queryset since the m2m won't have been saved by the admin form yet.
IOW, if you have something to do that depends on m2m being set, you'll have to put it in a distinct method and ensure that method get called when appropriate
About your code snippet:
1/ the recurrence_rules = EventSeries.objects.get(pk=self.event_series.pk) is just redundant, since you alreay have the very same object under the name self.event_series
2/ there's no need to call save on the events you create with Event.objects.create - the ModelManager.create method really create an instance (that is: save it to the database).

Reevaluating a model-level query

In brief: A model's method performs a query (returning the output of objects.filter()), but when the objects' values are changed in the database, the results of objects.filter() don't update until I bounce the server. How can I force the query to evaluate each time the method is called?
The details:
At the model level, I've defined a method to return all non-expired Announcement objects:
class AnnouncementManager(models.Manager):
# this is the method
def activeAnnouncements(self, expiry_time):
activeAnnouncements = self.filter(expires_at__gt=expiry_time).all()
return activeAnnouncements
class Announcement(models.Model):
...
expires_at = models.DateTimeField("Expires", null=True)
objects = AnnouncementManager()
I call this from a view with:
activeAnnouncements = Announcement.objects.activeAnnouncements()
However, when an Announcement object's data is updated in the database (e.g. expires_at is changed), the query still reflects the old data until the server is bounced. After reading http://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated, I tried to force the query to reevalute by updating the method as follows:
def activeAnnouncements(self, expiry_time):
# use boolean evaluation to force reevaluation of queryset
if self.filter(expires_at__gt=expires):
pass
activeAnnouncements = self.filter(expires_at__gt=expiry_time).all()
return activeAnnouncements
This had no effect.
Thanks for your help!
Update:
Can you please show the full code of where you are calling it?
This is the view which calls it:
#never_cache
def front_page(request):
'''
Displays the current announcements
'''
announcements = ''
activeAnnouncements = Announcement.objects.activeAnnouncements().order_by('-id')
if not request.user.get_profile().admin:
hide_before = request.user.get_profile().suppress_messages_before
if hide_before is not None:
activeAnnouncements = activeAnnouncements.filter(created_at__gt=hide_before)
if activeAnnouncements.count() > 0:
announcements = activeAnnouncements
else:
announcements = ""
return render_to(
request
, "frontpage.html"
, {
'announcements' : announcements
})
And here's the full version of the Announcement and AnnouncementManager models (excerpted above):
class AnnouncementManager(models.Manager):
# Get all active announcements (i.e. ones that have not yet expired)
def activeAnnouncements(self, expires=datetime.datetime.now()):
activeAnnouncements = self.filter(expires_at__gt=expires).all()
return activeAnnouncements
class Announcement(models.Model):
text = models.TextField()
subject = models.CharField(max_length=100)
expires_at = models.DateTimeField("Expires", null=True)
created_at = models.DateTimeField("Creation Time", auto_now_add=True)
created_by = models.ForeignKey(User, related_name="created_announcements")
updated_at = models.DateTimeField("Update Time", auto_now=True)
updated_by = models.ForeignKey(User, related_name="updated_announcements")
objects = AnnouncementManager()
def __unicode__(self):
return self.subject
Aha. The full version of the Manager method has a big difference from the one you originally posted, and it's there that the trouble is.
def activeAnnouncements(self, expires=datetime.datetime.now()):
This is one of the biggest Python gotchas: default function parameters are evaluated when the function is defined, not when it is called. So the default value for expiry will be set to whenever the server process was first started. Read the effbot's explanation of the problem. (Note it's a Python problem, not anything to do with Django querysets.)
Instead, do this:
def activeAnnouncements(self, expires=None):
if expires is None:
expires = datetime.datetime.now()
activeAnnouncements = self.filter(expires_at__gt=expires).all()
return activeAnnouncements
Is this an answer to your question?

Add extra information after submitting form

I have the following structure:
class FeatureType(models.Model):
type = models.CharField(max_length=20)
def __unicode__(self):
return self.type
class Feature(models.Model):
name = models.CharField(max_length=50)
type = models.ForeignKey(FeatureType)
premium = models.BooleanField("Premium Feature", default=False)
def __unicode__(self):
return self.name
What I want to do is when the user is adding a vehicle (the app is for a vehicle inventory), there's a large textbox that will be used to get a list of features from another website by the user copying and pasting them there.
I'm doing fine so far, but what I don't know how to do is, for each feature that's parsed from the textbox, the user will be able to set the type this feature belongs to. Here's my code so far:
vehicle_form = VehicleForm(request.POST or None)
photos = PhotosFormSet(request.POST or None, request.FILES or None)
features = FeaturesForm(request.POST or None)
if vehicle_form.is_valid() and photos.is_valid() and features.is_valid():
vehicle = vehicle_form.save(commit=False)
vehicle.save()
if features.cleaned_data['external']:
external_set = features.cleaned_data['external'].split('\r\n')
for feature in external_set:
#set featuretype somehow
vehicle_feature, created = Feature.objects.get_or_create(name=feature
, type = featuretype)
feature = vehicle.features.add(vehicle_feature)
photos = PhotosFormSet(request.POST, request.FILES, instance=vehicle)
photos.save()
So how can I enable choosing a feature type for each feature?
What I want to do, ideally, is to have existing features matched to the record...for those features that don't exist, the user will be redirected to another view that will enable him to set the type for each new feature and subsequently add it to the record.
UPDATE 1
I've modified the code a bit to look like this:
if features.cleaned_data['external']:
new_features = []
external_set = features.cleaned_data['external'].split('\r\n')
for feature in external_set:
try:
vehicle_feature = Feature.objects.get(external_name = feature)
feature = vehicle.features.add(vehicle_feature)
except Feature.DoesNotExist:
new_features.append(feature)
This takes care of getting the existing features....what I want to do now is to have all the features in new_features passed onto another form after the user saves the current record, where the user will enter further details for each feature.
In your FeaturesForm you can add something like:
feature_type = forms.ChoiceField(label="Feature Type",
choices=FeatureType.objects.values_list('id', 'type'))